Node.js HTTP 트랜잭션

katsukichi·2021년 3월 20일
0

CodeStates_IM

목록 보기
31/48

내가 사전에 알아야할 내용

  • 상식선에서 HTTP요청이 어떻게 동작하는지 알고있어야한다.
  • Node.js의 EventEmittersStreams에도 어느정도 익숙해야 한다. ( 익숙하지 않다면 관련 API문서를 미리 훑어보는편이 좋다.)

EventEmitters 에 대해서는

https://www.huskyhoochu.com/nodejs-eventemitter/

이분 블로그가 좋은거같다. 몇번 읽어보고 이해했는데

객체지향적인거같고, js버전의 에드이벤트리스너 느낌이다.

즉 어떤 이벤트를 발생시키면 해당 객체가 그것을 실행시킨다.(그이전에 .on메서드로 이벤트가 등록되어있어야한다.)

거기에 stream 개념

stream은 어떤 데이터든 데이터를 읽을 수 있는 상황이 되면 이벤트를 호출한다.

잘은 모르겠지만.

매번 에미터를 부른다는것이다. 데이터 보면 에미터불러주는 친구다.


서버생성

모든 노드 웹서버는 웹서버 객체를만들어야한다. 이때 createServer를 사용한다.


const http = require('http')

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

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

createServer가 반환한 Server객체는 EventEmitter이고 여기서는 약간 축약 문법을 사용한것.


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

기본은 이런형태가 오리지널이다.

메서드,URL,헤더

request 객체 에 프로퍼티로 들어있다.


const { method, url }  = request; // 해체할당

method는 . 뭐 GET,POST,OPTIONS 등등 ..

url은 세번째 슬래시(/) 이후의 나머지 전부라고 볼수있다.


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

헤더도 마찬가지이며,

클라이언트가 헤더를 어떻게했건간에 관계없이

모든 헤더는 소문자로만 표현된다.

일부 헤더를 반복해서 설정한다면 이 값은 헤어뎅따라 덮어씌워지거나 콤마로 구분된 문자열로 합쳐지는데

이게 문제가되면 rawHeaders 를 사용해아할수도있다.

요청 바디

바디를 받아오는게 생각보다 복잡하다.

약간 이벤트에미터에 대해서 잘알아야한다.

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

천천히 가보자. data라는 이벤트는 스트림이라는친구가 발견할때마다 호출해준다.

이때 우리는 이벤트리스너로 추가해준다.

먼저 chunk를 인자로 받아서 바디에 하나씩 추가해준다.

(쉽게생각하면 한글자씩 받아오는것) -> 버퍼개념 (물론 데이터도 문자열이나 이런식이아니다.)

이후 end는 body를 읽다가 종료됬을때 발생한다 (마찬가지로 스트림이 계속 읽고있다.)

그러면 on으로 추가해준다. 지금까지 저장한 body 배열에

js의 Beffer객체 프로토타입 concat매서드를 사용해서

아스키코드가 들어있는 데이터 배열을 문자열로 바꿔서 저장해준다.

요청의 에러 처리


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

listen

마지막으로 해당 서버를 listen 하고있으면 서버가 돌고있다고 표현할수있다.


const PORT = 5000;

const ip = 'localhost';

// ... 중략

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

HTTP상태코드 + 응답헤더설정 = 명시적인 헤더 데이터전송

response.statusCode = 404;
response.setHeader('Content-Type', 'application/json');
response.setHeader('X-Powered-By', 'bacon');

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

응답 바디


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>');

주의: 바디에 데이터 청크를 작성하기 전에 상태 코드와 헤더를 설정해야 합니다. HTTP 응답에서 바디 전에 헤더가 있으므로 이는 이치에 맞습니다.

응답의 에러 처리

응답객체도 마찬가지로 에러가있을수있다.


response.on('error', (err) => {
      console.error(err);
    });

어제 많이 본 에러

ERR_STREAM_WRITE_AFTER_END#
An attempt was made to call stream.write() after stream.end() has been called.

end요청이후에 write를 시도했다.

이게 생각보다 어렵다.

그리고 OPTIONS 메서드 (프리플라이트) 에 반응하게 하고
프리플라이트에도 헤더를 내려주고
본요청에도 헤더를 계속 내려줘야한다는점.

profile
front-back / end developer / Let's be an adaptable person

0개의 댓글