티스토리 뷰

Node.js 서버 만들기

https://nodejs.org/ko/docs/guides/anatomy-of-an-http-transaction 문서를 참고하여 Node.js의 HTTP 처리 과정을 정리해본다.

 

HTTP 트랜잭션 해부 | Node.js

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

nodejs.org

 

1. 서버 생성하기

모든 Node.js 웹 서버 애플리케이션은 웹 서버 객체를 만들어야 한다. 

cont http = require('http');

const cuteServer = http.createServer();
cuteServer.on('request', (req, res) => {
  // 매 http 요청마다 실행될 함수
});

// 위 코드를 축약해서 아래와 같이 사용한다.
const prettyServer = http.createServer((req, res) => {
  // 매 http 요청마다 실행될 함수
});

HTTP요청이 오면 Node.js가 알아서 request, response 객체를 전달해주며 'request'이벤트의 핸들러 함수를 호출한다. 지금까지 요청을 받기 위해 이벤트 리스너를 등록한 것이고, 이를 실제로 실행시키려면 서버 객체에서 listen 메서드를 호출해야 한다.

 

2. 서버 켜기

const http = require('http');

const prettyServer = http.createServer((req, res) => {
  // 매 http 요청마다 실행될 함수
});

prettyServer.listen(3000, () => {
  console.log(`Example server listening on port ${port}`)
})

server.listen() Possible signatures

listen 메서드는 다양한 인자를 받을 수 있다. 대부분은 서버가 사용하고자 하는 포트번호를 listen에 전송하면 된다. 

 

3. 요청 body 처리하기

const prettyServer = http.createServer((req, res) => {
  // 매 http 요청마다 실행될 함수
  let body = [];
  req.on('data', (chunk) => {
    body.push(chunk);
  }).on('end', () => {
    body = Buffer.concat(body).toString();
  // 여기서 `body`에 전체 요청 바디가 문자열로 담겨있다.
});
});

POST, PUT 등의 메서드는 요청에 body가 담겨있다. Node.js에서 위와 같은 로직으로 요청 body를 처리할 수 있다. 위 코드의 body를 이용하여 작업한다.

 

4. HTTP 상태 코드, 응답 헤더, 응답 바디 전달하기

const prettyServer = http.createServer((req, res) => {
  // 매 http 요청마다 실행될 함수
  // ...
  // 암묵적 헤더 설정
  res.statusCode = 404;
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('X-Powered-By', 'bacon');

  // 또는 명시적 헤더 전송
  res.writeHead(200, {
    'Content-Type': 'application/json',
    'X-Powered-By': 'bacon'
  });
});

HTTP 상태 코드를 따로 설정하지 않으면 200이 설정된다. 암묵적 헤더를 설정하면 Node.js가 응답 바디를 전송하기 전에 적절한 순간에 응답 헤더를 전송한다. 이는 Node.js에게 의존하고 있다고 할 수 있고, 원한다면 writeHead 메서드를 통해 명시적으로 헤더를 전송할 수 있다. 암묵적이든 명시적이든 헤더를 설정했으면 응답 바디를 전송할 준비가 된 것이다. 

const prettyServer = http.createServer((req, res) => {
  // 매 http 요청마다 실행될 함수
  // ...
  // 응답 바디 전송
  res.write(JSON.stringify(responseBody));
  res.end();
  
  // 위 두 줄은 다음 한 줄로 대체할 수도 있다.
  res.end(JSON.stringify(responseBody))
});

응답 헤더를 설정했다면 위와 같이 응답 바디를 전송한다.

 

Express 서버 만들기

Express는 Node.js 환경에서 웹 서버 또는 API 서버를 제작하기 위해 사용되는 인기있는 프레임워크이다. 

npm install express

 

1. 서버 생성하고 서버 켜기

const express = require('express')
const prettyApp = express()
const port = 3000

prettyApp.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

Node.js 서버와 비슷하다.

 

2. 라우팅하기

// Node.js 서버
const prettyServer = http.createServer((req, res) => {
  // 매 http 요청마다 실행될 함수
  if(req.url === '/'){
    if(req.method === 'GET'){
      // GET /일 때 수행할 작업
    } else if(req.method === 'POST'){
      // POST /일 때 수행할 작업
    }
  }
});

url의 엔드포인트가 /이고 메서드가 GET일 때, POST일 때 각각 요청을 처리하기 위한 Node.js 서버의 코드이다. if-else를 이용하여 인덴트가 많고 코드가 길어져서 다소 복잡하다. Express는 프레임워크 자체에서 라우터 기능을 제공한다. 

// Express 서버
// ...
const prettyRouter = express.Router();

prettyRouter.get('/', (req, res) => {
  // GET /일 때 수행할 작업
}
prettyRouter.post('/', (req, res) => {
  // POST /일 때 수행할 작업
}

이처럼 메서드와 경로에 따라서 처리해주는 과정을 라우팅(라우트를 처리한다)이라고 한다.

 

3. 미들웨어 사용하기

미들웨어는 middle이라는 이름처럼 요청과 응답의 중간에 위치한다. 요청과 응답의 중간에서 실행된다. 필요한 중간 작업을 미들웨어를 사용하여 편리하게 코드를 작성할 수 있다. 미들웨어는 Express의 강력한 장점이다.

예를 들어서 모든 요청마다 url과 메서드를 출력하는 console.log(`path: ${req.url}, method: ${req.method}`) 를 실행하고 싶다면 모든 핸들러에 이 한 줄을 적어주는 것이 아니라, 이를 printRequest라는 함수로 만들어서 매 요청마다 이 함수가 실행되도록 미들웨어를 작성한다. 미들웨어를 사용하는 방법은 다음과 같이 간단하다.

// ...
const printRequest = (req, res, next) => {
  console.log(`path: ${req.url}, method: ${req.method}`);
  next();
};

prettyApp.use(printRequest); // 모든 요청에 대해 printRequest 미들웨어를 실행한 후 요청핸들러 실행

prettyApp.get('/', (req, res) => {
  // GET /일 때 수행할 작업
});
prettyApp.post('/join', (req, res) => {
  // POST /일 때 수행할 작업
});

 

4. 요청 body 처리하기

// ...
const jsonParser = express.json(); // body를 처리하기 위한 미들웨어
// 에러가 난다면 option을 설정해준다. const jsonParser = express.json({strict: false});

prettyApp.post('/api/users', jsonParser, function (req, res) {
  // POST /api/users일 때 수행할 작업
})

Node.js에서 요청 body를 처리한 것과 달리 직관적이고 짧은 코드로 body를 처리할 수 있다. Express의 미들웨어를 사용한다. 3번의 prettyApp.use(미들웨어) 를 사용하면 모든 요청에 대해 미들웨어를 항상 수행하는 것인데, 위 코드처럼 요청과 응답에 추가적으로 미들웨어를 기입하면 미들웨어가 이 특정 요청에 대해서만 실행된다.

 

5. HTTP 상태 코드, 응답 헤더, 응답 바디 전달하기

prettyApp.get('/', (req, res) => {
  // GET /일 때 수행할 작업
  // 다음과 같이 다양한 Express 응답 메서드가 있다. 필요한 것을 골라서 사용한다.
  res.send('Hello World!');
  res.json({msg: 'This is CORS-enabled for a Single Route'});
  res.end();
  res.status(400).send('invalid user')
});

res.json(something) 은 something을 JSON형식으로 바꾸어 보내준다.
res.end() 는 전달할 응답 데이터가 없는데 응답을 끝내고 싶을 때 사용한다.
res.send(something) 은 우리가 보내는 something이 Buffer,String, Object, Array인지 파악하여 자동으로 Content-type을 지정해준다.

 

반응형
댓글