HTTP 트랜젝션 해부

Jelkov Ahn·2021년 10월 22일
0

HTTP / 네트워크

목록 보기
7/11
post-thumbnail

목적: HTTP가 어떻게 작동하는지 ?

서버생성 (서버 객체 생성)

createServer사용

node 웹 서버 어플리케이션은 웹 서버 객체를 만들어야 한다. 아래와 같이 만든다.

const http = require('http');

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

    • 서버에 요청하고 응답 받기 위해서 node.js의 http 모듈을 이용해 웹 서버를 만듭니다.
      (fs 모듈로 파일을 쓰고 있는데 사용하는것과 비슷하다.)
    • 이 서버로 오는 HTTP 요청마다 createServer에 전달된 함수가 한 번씩 호출됩니다.
    • 이때 node가 트랙제션을 다루려고 requestresponse객체를 전달하며 요청 핸들러 함수를 호출한다.
  • Server객체

    • 사실 createServer가 반환한 Server 객체는 EventEmitter이고, 여기서는 server 객체를 생성하고 리스너를 추가하는 축약 문법을 사용한 것입니다.
    • server 객체는 EventEmitter 객체를 기반으로 만들어졌으므로 이벤트를 연결할 수 있습니다.

Request(메서드, URL , 헤더)

  • request 안에 여러 객제가 있다.
  • requestIncomingMessage의 인스턴스 이면서 ReadableStream 이다.
    method / URL / header 등등
const { method, url } = request;
  • [주의] IncomingMessage의 인스턴스가 request객체

<What is IncomingMessage??>

An IncomingMessage object is created by http.Server or http.ClientRequest and passed as the first argument to the 'request' and 'response' event respectively. It may be used to access response status, headers and data.

  • 메서드 / url
    여기서 method는 항상 일반적인 HTTP 메서드/동사가 될 것입니다. url은 전체 URL에서 서버, 프로토콜, 포트를 제외한 것으로, 세 번째 슬래시 이후의 나머지 전부라고 볼 수 있습니다.

  • 헤더(모든헤더는 소문자로만 표현된다)

const { headers } = request;
const userAgent = headers['user-agent'];

request body

request 객체는 ReadableStream 인터페이스를 구현하고 있습니다.

  • ReadableStream
    Readable streams are an abstraction for a source from which data is consumed.

  • request에 이벤트 리스너를 등록하거나 다른 스트림에 파이프로 연결할 수 있습니다.

  • request의 'data'와 'end' 이벤트에 이벤트 리스너를 등록해서 데이터를 받을 수 있습니다.

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

각 'data' 이벤트에서 발생시킨 청크는 Buffer입니다. 이 청크가 문자열 데이터라는 것을 알고 있다면 이 데이터를 배열에 수집한 다음 'end' 이벤트에서 이어 붙인 다음 문자열로 만드는 것이 가장 좋습니다.

오류에 대한 간단한 설명

(항상 오류는 발생할 수 있다는 것을 명심하고 오류를 처리해야 합니다.)

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

종합

const http = require('http');

http.createServer((request, response) => {
  const { headers, method, url } = request;
  let body = [];
  request.on('error', (err) => {
    console.error(err);
  }).on('data', (chunk) => {
    body.push(chunk);
  }).on('end', () => {
    body = Buffer.concat(body).toString();
    // 여기서 헤더, 메서드, url, 바디를 가지게 되었고
    // 이 요청에 응답하는 데 필요한 어떤 일이라도 할 수 있게 되었습니다.
  });
}).listen(8080); // 이 서버를 활성화하고 8080 포트로 받습니다.
  • 여기에는 response 객체가 없기때문에 요청에 응답하지 않습니다. 클라이언트에서 요청만 보내고 받을게 없어서 타임아웃에 걸리게 된다.

Response

response - ServerResponse의 인스턴스이면서 WritableStream입니다

HTTP 상태코드

  • 기본 HTTP 상태코드 항상 200

  • 상태 코드를 변경하려면 statusCode 프로퍼티를 설정해야 합니다.

response.statusCode = 404; // 클라이언트에게 리소스를 찾을 수 없다고 알려줍니다.

응답 헤더 설정 (대소문자 무관)

response.setHeader('Content-Type', 'application/json');
response.setHeader('X-Powered-By', 'bacon');
  • 여러번 설정하면 마지막에 설정한 값을 보낸다.

명시적인 헤더 데이터 전송

  • 명시적으로 응답 스트림에 헤더를 작성할 수 있습니다. 헤더를 작성하는 writeHead 메서드가 있습니다. 이 메서드는 스트림에 상태 코드와 헤더를 작성합니다.
response.writeHead(200, {
  'Content-Type': 'application/json',
  'X-Powered-By': 'bacon'
});

응답 바디 전송

  • response 객체는 WritableStream이므로 클라이언트로 보내는 응답 바디는 일반적인 스트림 메서드를 사용해서 작성합니다.
response.write('<html>');
response.write('<body>');
response.write('<h1>Hello, World!</h1>');
response.write('</body>');
response.write('</html>');
response.end();

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

response.end('<html><body><h1>Hello, World!</h1></body></html>');
  • 한번에 전달이 가능하다.

마무리

아래 원본 사이트에서 예제를 보면서 다시한번 확인해보자.

원본: https://nodejs.org/ko/docs/guides/anatomy-of-an-http-transaction/

참고: https://close-up.tistory.com/entry/Nodejs-HTTP-%EB%AA%A8%EB%93%88

profile
끝까지 ... 가면 된다.

0개의 댓글