Jieunny의 블로그

S2) Unit 10. [실습] Mini Node Server 본문

CodeStates/Training

S2) Unit 10. [실습] Mini Node Server

Jieunny 2023. 2. 6. 17:00

📣  Mini Node Server 만들기

1️⃣ 서버 생성

const http = require('http');

const server = http.createServer((request, response) => {
  // 여기서 작업이 진행됩니다!
});

➰ 모든 node 웹 서버 애플리케이션은 웹 서버 객체를 만들어야 하는데, 이 때 createServer를 이용한다.

➰ 이 서버로 오는 HTTP 요청마다 createServer에 전달된 함수가 한 번씩 호출된다.

➰ createServer가 반환한 Server 객체는 EventEmitter이다 (Server 객체를 생성하고 리스너를 추가하는 축약 문법 사용)

➕ EventEmitter 란?

더보기

특정 이벤트에 리스너 함수를 달아서, 이벤트가 발생했을 때 이를 캐치할 수 있도록 만들어진 api

➰ HTTP 요청이 서버에 오면 node가 트랜잭션을 다루려고 request와 response 객체를 전달하며 요청 핸들러 함수를 호출한다.

 

2️⃣ 요청 바디

➰ 핸들러에 전달된 request 객체는 ReadableStream 인터페이스를 구현하고 있다.

➰ 이 스트림에 이벤트 리스너를 등록하거나 다른 스트림에 연결할 수 있다.

➰ 스트림의 'data' 와 'end' 이벤트에 이벤트 리스터를 등록해서 데이터를 받을 수 있다.

➕ stream 이란?

더보기

➰ 스트리밍 데이터로 작업하기 위한 추상적인 인터페이스

➰ 통일된 방식으로 데이터를 다루기 위한 가상의 개념

➰ stream은 읽을 수 있거나, 쓸 수 있거나, 둘 다 가능할 수 있다.

➰ 모든 stream들은 EventEmitter의 인스턴스이므로 이벤트 핸들러를 작성할 수 있다.

let body = [];
request.on('data', (chunk) => {
  body.push(chunk);
}).on('end', () => {
  body = Buffer.concat(body).toString();
  // 여기서 `body`에 전체 요청 바디가 문자열로 담겨있습니다.
});

➰ 각 'data' 이벤트에서 발생시킨 청크는 Buffet이다.

➰ 이 청크가 문자열 데이터라는 것을 알고 있다면, 이 데이터를 배열에 수집한 다음 'end' 이벤트에서 이어 붙인 다음 문자열로 만드는 것이 가장 좋다.

 

3️⃣ 오류에 대한 간단한 설명

request 스트림의 오류가 발생하면 스트림에서 'error' 이벤트가 발생하면서 오류를 전달핟나.

이벤트에 리스너가 등록되어 있지 않다면 Node.js 프로그램을 종료시킬 수도 있는 오류를 던질 것이다.

그러므로 단순히 오류를 로깅만 하더라도 요청 스트림에 'error' 리스너를 추가해야 한다.

request.on('error', (err) => {
  // 여기서 `stderr`에 오류 메시지와 스택 트레이스를 출력합니다.
  console.error(err.stack);
});

 

4️⃣ 명시적인 헤더 데이터 전송

➰ 헤더를 작성하는 writeHead 메서드를 이용한다.

➰ 이 메스드는 스트림에 상태 코드와 헤더를 작성한다.

response.writeHead(200, {
  'Content-Type': 'application/json',
  'X-Powered-By': 'bacon'
});

 

5️⃣ 응답 바디 전송

➰ 스트림의 end 함수에 스트림에 보낼 데이터의 마지막 비트를 선택적으로 전달 할 수 있다.

// 1
response.write('<html>');
response.write('<body>');
response.write('<h1>Hello, World!</h1>');
response.write('</body>');
response.write('</html>');
response.end();

// 2
response.end('<html><body><h1>Hello, World!</h1></body></html>');

 

📣  basic-server.js

const http = require('http');

const PORT = 4999;

const ip = 'localhost';

const server = http.createServer((request, response) => {

  if(request.method === 'OPTIONS'){
    response.writeHead(200, defaultCorsHeader);
    response.end();
  }

    else if(request.method === 'POST'){
      if(request.url === '/upper'){
        let body = [];
        request.on('data', (chunk) => {
          body.push(chunk);
        }).on('end', () => {
          body = Buffer.concat(body).toString().toUpperCase();
      // 여기서 `body`에 전체 요청 바디가 문자열로 담겨있습니다.
          response.end(body);
        });
        console.log(body);
      }

      else if(request.url === '/lower'){
        let body = [];
        request.on('data', (chunk) => {
          body.push(chunk);
        }).on('end', () => {
          body = Buffer.concat(body).toString().toLowerCase();
          response.end(body);
        });
      }
    }

    else{
        request.on('error', (err) => {
        // 여기서 `stderr`에 오류 메시지와 스택 트레이스를 출력합니다.
        console.error(err.stack);
      });
    }

  // console.log(
  //   `http request method is ${request.method}, url is ${request.url}`
  // );
  response.writeHead(200, defaultCorsHeader);
  // response.end('hello mini-server sprints');
});

server.listen(PORT, ip, () => {
  console.log(`http server listen on ${ip}:${PORT}`);
});

const defaultCorsHeader = {
  '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
};

 

📣  시연 화면

 

 

📚 참고

HTTP 트랜잭션 해부 https://nodejs.org/ko/docs/guides/anatomy-of-an-http-transaction/