[TIL] ChatterBox Server : CommonJS & ExpressJS

Junyong-Ahn·2019년 12월 6일
0

과거

목록 보기
2/5

Common JS version

const fs = require('fs');
const path = require('path');
//리스너

const mimeType = {
  '.html' : 'text/html',
  '.css'  : 'text/css',
  '.js'   : 'text/javascript',
  '':'text/html'
}
let output = {
  results: []
};

fs.readFile('./text.json', 'utf8', function(err, data){
  if (err) {
    return;
  } else if (data.length > 0 && typeof(JSON.parse(data)) === 'object'){
    console.log(data);
    output = JSON.parse(data);
  }
});

const requestHandler =function(request, response){
  console.log(
    'Serving request type ' + request.method + ' for url ' + request.url
  );
  const statusCode = 200;
  const headers = defaultCorsHeaders;
  headers['Content-Type'] = 'text/plain';

  if(request.url === '/classes/messages'){
    if(request.method === 'OPTIONS'){
      response.writeHead(statusCode, headers);
      response.end();
    }
    else if(request.method === 'POST'){
      let message ='';
      request.on('data', chunk =>{
        message += chunk;
      }).on('end', () => {
        message = JSON.parse(message);
        output.results.push(message);
        fs.writeFile('./text.json', JSON.stringify(output),'utf8', function(err){
          console.log('비동기적 파일 쓰기 완료');
          response.writeHead(201, headers);
          response.end();
        });
      })
    }
    else if(request.method === 'GET'){
        response.writeHead(statusCode, headers);
        response.end(JSON.stringify(output));
    }else{
      console.log('ERROR');
      response.writeHead(404, headers);
      response.end();
    }
  }
  else if(request.url === '/'){
    const filePath = path.join(__dirname, '../public/index.html') 
    fs.readFile(filePath, (err, data) => {
      if (err) throw err;
      response.end(data)
    })
  }else if(request.url === '/codestates'){
    response.writeHead(404, headers);
    response.end();
  }
  else{
    const ext = path.parse(request.url).ext;
    const publicPath = path.join(__dirname, '../public');

    if(Object.keys(mimeType).includes(ext)){
      fs.readFile(`${publicPath}${request.url}`, (err, data) => {
        if(err){
          response.end('Not Found');
        }
        else{
          headers['Content-Type'] = mimeType[ext];
          response.writeHead(200, headers);
          response.end(data);
        }
      })
    }
  }
};
const defaultCorsHeaders = {
  'access-control-allow-origin': '*',
  'access-control-allow-methods': 'GET, POST, PUT, DELETE, OPTIONS',
  'access-control-allow-headers': 'content-type, accept',
  'access-control-max-age': 10 // Seconds.
};
module.exports = requestHandler;

Express JS Version

const fs = require('fs');
const path = require('path');
const express = require('express');
const app = express();
const cors = require('cors');
const PORT = 3000;
// request 의 body를 읽어오기 위한 패키지
var bodyParser = require('body-parser');

const corsOptions = {
  'optionSuccessStatus' : 200,
  'access-control-allow-origin': '*',
  'access-control-allow-methods': 'GET, POST, PUT, DELETE, OPTIONS',
  'access-control-allow-headers': 'content-type, accept',
  'access-control-max-age': 10 // Seconds.
}

// 데이터 보관 => 계속 초기화 돼서 메시지를 출력할 수 없다.
let output = {
  results: []
};
//text.json 파일이 비어있을 때와, 데이터를 가지고 있을 때를 구분한다.
fs.readFile('./text.json', 'utf8', function(err, data){
  if (err) {
    return;
  } else if (data.length > 0 && typeof(JSON.parse(data)) === 'object'){
    // 이미 데이터를 가지고 있으면 output에 덮어씌운다
    output = JSON.parse(data);
  }
});

// cors 대응

app.use(cors(corsOptions));
// static 파일폴더를 지정해준다
app.use(express.static('public'))
//request의 body에 접근할 수 있다.
app.use(bodyParser.json());

// options 메서드가 왔을 때에 대한 응답
app.options((request, response) => {
  console.log(request.method);
  response.send(cors(defaultCorsHeaders));
});
// 모든 요청에 대해서 콘솔 띄우기
app.use((request, response, next) => {
  console.log('Serving request type ' + request.method + ' for url ' + request.url);
  next();
});
app.get('/', (request, response) => {
  const publicPath = path.join(__dirname, '../public/index.html');
  response.sendFile(publicPath);
});
app.get('/css/style.css', (request, response) => {
  const publicPath = path.join(__dirname, '../public/css/style.css');
  response.sendFile(publicPath);
});
app.get('/js/script.js', (request, response) => {
  const publicPath = path.join(__dirname, '../public/js/script.js');
  response.sendFile(publicPath);
});
// '/classes/messages' 로 get 요청이 들어오면  outout보내기
app.get('/classes/messages', (request, response, next) => {
    fs.readFile('./text.json', 'utf8', function(err, data){
        if (err){
          return;
        } else if (data.length > 0 && typeof(JSON.parse(data)) === 'object'){
          output = JSON.parse(data);
        }
        response.send(output);
    });
});

// '/classes/messages' 로 post 요청이 들어오면 fs에 write
app.post('/classes/messages', (request, response) => {
    output.results.push(request.body);
    fs.writeFile('./text.json', JSON.stringify(output),'utf8', function(err){
      if(err) throw err;
      console.log('비동기적 파일 쓰기 완료');
      response.send();
    });

});


app.listen(PORT, function(){
  console.log(`server listen on ${PORT}`);
})

const defaultCorsHeaders = {
  'access-control-allow-origin': '*',
  'access-control-allow-methods': 'GET, POST, PUT, DELETE, OPTIONS',
  'access-control-allow-headers': 'content-type, accept',
  'access-control-max-age': 10 // Seconds.
};

가장 괴롭혔던 문제

클라이언트에서 유저의 메시지를 보내도 파일시스템에 기록을 할 수도, 불러올 수도 없었다.

  1. 초기 app.post 코드 => TypeError: Converting circular structure to JSON 발생
app.post('/classes/messages', (request, response) => {
  output.results.push(request);
  fs.writeFile('./text.json', JSON.stringify(output),'utf8', function(err){
    if(err) throw err;
    response.send();
  });
});

위 코드 세번째 줄의 JSON.stringify(output)에서 TypeError: Converting circular structure to JSON 에러가 발생했다. 이 타입에러가 뜨는 이유는 자신을 참조하는 객체를 JSON화 하려고 할 때 발생한다고 한다. 파일시스템 메서드가 비동기로 실행되기 때문에 발생하는 문제라고 생각해서 output.result.push(request)를 fs.writeFile안으로 옮겼고, 에러는 해결되었다.

  1. output.results.push(request)를 fs.writeFile안으로 옮김 => 타입에러는 사라졌으나, 파일시스템에 데이터를 저장하지 못했다.
app.post('/classes/messages', (request, response) => {
  fs.writeFile('./text.json', JSON.stringify(output),'utf8', function(err){
    if(err) throw err;
    output.results.push(request);
    response.send();
  });
});

타입에러는 해결됐지만, 파일시스템에 어떠한 것도 저장되지 않았다. 따라서 클라이언트에서 메시지를 전송해도 그에 대한 응답으로 어떤 메시지도 받을 수 없었다.

  1. output에 넣어야 할 정보는 request가 아닌 request.body 였다.
const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.post('/classes/messages', (request, response) => {
  output.results.push(request.body);
  fs.writeFile('./text.json', JSON.stringify(output),'utf8', function(err){
    if(err) throw err;
    response.send();
  });
});

output에 요청메시지(request)를 통째로 넣었기 때문에 위 두가지 문제에 부딪혔던 것 같다. output에 넣어야할 것은 요청메시지 자체가 아니라 요청메시지의 body 프로퍼티(request.body)이다. request.body를 사용해야한다는 것은 알고 있었지만, console.log(request.body)undefined가 나오고 console.log(request)를 해봐도, request에는 body라는 프로퍼티가 없었기 때문에 request자체를 이용했다. request.body를 사용하려면 body-parser를 이용해야한다.const bodyParser = require('body-parser'); app.use(bodyParser.json()); 두줄의 코드를 추가했고, request.body를 사용해서 문제를 해결했다.

0개의 댓글