HTTP Transection

μš”μ²­ 처리

μ„œλ²„μ˜ 생성

λͺ¨λ“  node μ›Ή μ„œλ²„ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ€ μ›Ή μ„œλ²„ 객체λ₯Ό λ§Œλ“€μ–΄μ•Ό ν•©λ‹ˆλ‹€.
μ΄λ•Œ createServer λ₯Ό μ΄μš©ν•©λ‹ˆλ‹€.

const http = require('http');
const server = http.createServer((request, response) => {
  // Work Process
});

μ„œλ²„λ‘œ μ˜€λŠ” λͺ¨λ“  HTTP μš”μ²­ λ§ˆλ‹€ createServer 에 μ „λ‹¬λœ ν•¨μˆ˜κ°€ ν•œλ²ˆμ”© ν˜ΈμΆœλœλ‹€.
createServer κ°€ λ°˜ν™˜ν•œ Server κ°μ²΄λŠ” EventEmitter 이고 server 객체λ₯Ό μƒμ„±ν•˜κ³  λ¦¬μŠ€λ„ˆλ₯Ό μΆ”κ°€ν•˜λŠ” μΆ•μ•½ 문법이닀.

EventEmitter μ΄λž€ ?

EventEmitterλŠ” 이벀트 λͺ¨λ“ˆμ˜ μ˜ν•΄ μ •μ˜ 되며 μƒˆλ‘œμš΄ μ΄λ²€νŠΈκ°€ μΆ”κ°€λ˜κ±°λ‚˜ μ‚­μ œλ  λ•Œ 이벀트λ₯Ό λ‚΄λ³΄λƒ…λ‹ˆλ‹€.

const http = require('http');
const server = http.createServer();
server.on('request', (req, res) => {
  // Work Process
});

HTTP μš”μ²­μ΄ μ„œλ²„μ— 였면 node κ°€ νŠΈλžœμž­μ…˜μ„ 닀루렀고 request 와 response 객체λ₯Ό μ „λ‹¬ν•˜λ©° μš”μ²­ ν•Έλ“€λŸ¬ ν•¨μˆ˜λ₯Ό 호좜 ν•©λ‹ˆλ‹€.

Method, URL, Header 의 처리

μš”μ²­μ„ μ²˜λ¦¬ν•  λ•Œ, μš°μ„ μ€ Method 와 URL 을 ν™•μΈν•œ ν›„ 이와 κ΄€λ ¨λœ μž‘μ—…μ„ μ‹€ν–‰ν•©λ‹ˆλ‹€.
node λŠ” request 객체에 λŒ€λΆ€λΆ„μ˜ ν”„λ‘œνΌν‹°λ₯Ό λ„£μ–΄λ‘λ―€λ‘œ κΊΌλ‚΄μ„œ μ‚¬μš©ν•˜λ©΄ λœλ‹€.

const {method, url} = request;

request κ°μ²΄λŠ” IncomingMessage 의 μΈμŠ€ν„΄μŠ€μ΄λ‹€.

IncomingMessage Class 의 νŠΉμ§•

  • HTTP 에 μ˜ν•΄ μƒμ„±λœλ‹€.
  • νŠΉμ • 객체의 첫번째 λ³€μˆ˜λ‘œ μ „λ‹¬λ˜λŠ” 인수 (SERVER http.ClientRequest request event response event)
  • μ‘λ‹΅μƒνƒœ 및 헀더, 데이터 등을 μ•‘μ„ΈμŠ€ ν•˜λŠ”λ° μ‚¬μš© ν•œλ‹€.

헀더 λ˜ν•œ request κ°μ²΄μ—μ„œ μ–»μ–΄μ˜¨λ‹€.

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

TIP

ν΄λΌμ΄μ–ΈνŠΈκ°€ μ„€μ •ν•œ 헀더 ν”„λ‘œνΌν‹°λŠ” λŒ€μ†Œλ¬Έμž ꡬ뢄없이 μ†Œλ¬Έμžλ‘œλ§Œ ν‘œν˜„ λœλ‹€.
일뢀 헀더 정보λ₯Ό λ°˜λ³΅ν•΄μ„œ μ„€μ •ν•˜λ©΄ overwrite ν•˜κ±°λ‚˜ csv ν˜•νƒœλ‘œ ꡬ성될 수 μžˆλ‹€. 이런 κ²½μš°μ—λŠ” rawHeaders λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

Request Body 의 처리

post ν˜Ήμ€ put μš”μ²­μ‹œ ν•Έλ“€λŸ¬μ— μ „λ‹¬λœ request κ°μ²΄λŠ” ReadableStream μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜κ³  μžˆλ‹€.
이 μŠ€νŠΈλ¦Όμ— EventListener λ₯Ό λ“±λ‘ν•˜κ±°λ‚˜ λ‹€λ₯Έ 슀트림의 νŒŒμ΄ν”„λ‘œ μ—°κ²° ν•  수 μžˆλ‹€.

각 data μ΄λ²€νŠΈμ—μ„œ λ°œμƒμ‹œν‚¨ μ²­ν¬λŠ” Buffer 이며 μ΄λŠ” λ¬Έμžμ—΄ 데이터이닀.
μ΄λŠ” end μ΄λ²€νŠΈμ—μ„œ 이어 뢙인 λ‹€μŒμ— λ¬Έμžμ—΄λ‘œ λ§Œλ“œλŠ”κ²Œ κ°€μž₯ μ’‹λ‹€.

let body = [];

request.on('data', (chunk) => {
  body.push(chunk);
}).on('end', () => {
  // `body` 에 전체 μš”μ²­ λ°”λ””κ°€ λ¬Έμžμ—΄λ‘œ 담겨 μžˆλ‹€.
  body = Buffer.concat(body).toString();
});

였λ₯˜μ˜ κ΄€ν•œ 처리

request μŠ€νŠΈλ¦Όμ—μ„œ 였λ₯˜κ°€ λ°œμƒν•˜λ©΄ error μ΄λ²€νŠΈκ°€ λ°œν–‰ν•˜λ©΄μ„œ 였λ₯˜λ₯Ό μ „λ‹¬ν•œλ‹€.
λ³„λ„μ˜ 이벀트 λ¦¬μŠ€λ„ˆκ°€ λ“±λ‘λ˜μ–΄ μžˆμ§€ μ•Šλ‹€λ©΄ 였λ₯˜λ₯Ό λ±‰μœΌλ©΄μ„œ Node.js λ₯Ό μ’…λ£Œμ‹œν‚¨λ‹€.

request.on('error', (error) => {
  console.error(error.stack);
});

HTTP μš”μ²­ μ½”λ“œ 정리

const http = require('http');

http.createServer((request, response) => {
  const {headers, method, url} = request;
  
  let body = [];

  request.on('error', (error) => {
    console.error(error.stack);
  }).on('data', (chunk) => {
    body.push(chunk);
  }).on('end', () => {
    body = Buffer.concat(body).toString();

    /**
     *  헀더, λ©”μ„œλ“œ, μš”μ²­κ²½λ‘œ, λ°”λ”” 등을 κ°€μ§€κ²Œ λ˜μ—ˆμœΌλ©° 
     *  이 μš”μ²­μ— μ‘λ‹΅ν•˜λŠ” μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
     */
  })
}).listen(8080);

이 μ½”λ“œλŠ” μš”μ²­ 받을 수 μžˆμ§€λ§Œ μš”μ²­ν•œ λ””λ°”μ΄μŠ€(ν΄λΌμ΄μ–ΈνŠΈ) 에 응닡 ν•˜λŠ” 둜직이 μ—†κΈ° λ•Œλ¬Έμ— νƒ€μž„μ•„μ›ƒμ΄ 걸릴것 μž…λ‹ˆλ‹€.

응닡 처리

응닡 μƒνƒœ μ½”λ“œ

λ³„λ„μ˜ 섀정이 μ—†μœΌλ©΄ HTTP 응닡 μ½”λ“œλŠ” 200 으둜 κ³ μ • λ©λ‹ˆλ‹€.
μƒνƒœ μ½”λ“œλ₯Ό λ³€κ²½ ν•˜λ €λ©΄ statusCode ν”„λ‘œνΌν‹°λ₯Ό μ„€μ •ν•΄μ•Ό ν•©λ‹ˆλ‹€.

// λ¦¬μ†ŒμŠ€λ₯Ό μ°Ύμ„μˆ˜ μ—†μŒ
response.statusCode = 404;

응닡 헀더 μ„€μ •

setHeader λ©”μ„œλ“œλ‘œ 헀더λ₯Ό μ„€μ • ν•œλ‹€.

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 κ°μ²΄λŠ” WriteableStream μ΄λ―€λ‘œ ν΄λΌμ΄μ–ΈνŠΈλ‘œ λ³΄λ‚΄λŠ” 응닡 λ°”λ””λŠ” 일반적인 슀트림 λ©”μ„œλ“œλ₯Ό μ΄μš©ν•˜μ—¬ μž‘μ„± ν•©λ‹ˆλ‹€.

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

μœ„ μ½”λ“œλŠ” μ•„λž˜μ™€ 같이 μž‘μ„±ν•΄λ„ λ™μΌν•˜λ‹€.

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

였λ₯˜μ— κ΄€ν•œ 처리

response μŠ€νŠΈλ¦Όλ„ error 이벀트λ₯Ό λ°œμƒμ‹œν‚¬μˆ˜ 있고 λ•Œλ‘œλŠ” 이 였λ₯˜λ„ μ²˜λ¦¬ν•΄μ•Ό ν•©λ‹ˆλ‹€.
request μŠ€νŠΈλ¦Όμ— λŒ€ν•œ 였λ₯˜μ™€ λ™μΌν•˜κ²Œ 적용이 κ°€λŠ₯ν•©λ‹ˆλ‹€.

ν˜„μž¬κΉŒμ§€ μ μš©μ½”λ“œ

const http = require('http');

http.createServer((request, response) => {
  const { headers, method, url } = request;
  let body = [];

  request.on('error', (error) => {
    console.error(error);
  }).on('data', (chunk) => {
    body.push(chunk);
  }).on('end', () => {
    body = Buffer.concat(body).toString();

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

    response.statusCode = 200;
    response.setHeader('Content-Type', 'application/json');

    // μœ„ λ‘μ€„μ˜ μ½”λ“œλ₯Ό ν•œμ€„λ‘œ κ°€λŠ₯
    // response.writeHead(200, {'Content-Type': 'application/json'});

    const responseBody = { headers, method, url, body };

    response.write(JSON.stringify(responseBody));
    response.end();

    // μœ„ λ‘μ€„μ˜ μ½”λ“œλ₯Ό ν•œμ€„λ‘œ κ°€λŠ₯
    // response.end(JSON.stringify(responseBody));

  });
}).listen(8080);

에코 μ„œλ²„ λ§Œλ“€κΈ°

μ—μ½”μ„œλ²„λž€ μš”μ²­ 받은 데이터λ₯Ό κ·ΈλŒ€λ‘œ μ‘λ‹΅μœΌλ‘œ λŒλ €λ³΄λ‚΄λŠ” μ„œλ²„μ΄λ‹€.
μ•žμ—μ„œ ν–ˆλ˜κ²ƒ 처럼 μš”μ²­ μŠ€νŠΈλ¦Όμ—μ„œμ˜ 데이터λ₯Ό 가져와 응닡 μŠ€νŠΈλ¦Όμ— μ“΄λ‹€.

const http = require('http');

http.createServer((request, response) => {
  let body = [];
  
  request.on('data', (chunk) => {
    body.push(chunk);
  }).on('end', () => {
    body = Buffer.concat(body).toString();
    response.end(body);
  });
}).listen(8080);

μœ„ μ½”λ“œλ₯Ό λ‹€μŒ 쑰건에 따라 에코 응닡을 λ³΄λ‚΄λŠ”κ²ƒμœΌλ‘œ μˆ˜μ •ν•œλ‹€.

  • μš”μ²­ λ©”μ„œλ“œκ°€ POST 인 경우
  • URL 이 /echo 인 경우
const http = require('http');

http.createServer((request, response) => {
  if (request.method === 'POST' && request.url === '/echo') {
    let body = [];
    request.on('data', (chunk) => {
      body.push(chunk);
    }).on('end', () => {
      body = Buffer.concat(body).toString();
      response.end(body);
    });
  } else {
    response.statusCode = 404;
    response.end();
  }
}).listen(8080);

μœ„μ˜ λ°©λ²•μœΌλ‘œ λΌμš°νŒ…μ„ ν•˜κ³  μžˆμ§€λ§Œ expressν”„λ ˆμž„μ›Œν¬λ‚˜ routerλΌμ΄λΈŒλŸ¬λ¦¬λ¦‰ ν†΅ν•΄μ„œ μ²˜λ¦¬λ„ κ°€λŠ₯ν•˜λ‹€.

request κ°μ²΄λŠ” ReadableStream 이고 response κ°μ²΄λŠ” WriteableStream μ΄λ―€λ‘œ pipe λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

const http = require('http');

http.createServer((request, response) => {
  if (request.method === 'POST' && request.url === '/echo') {
    request.pipe('response');
  } else {
    response.statusCode = 404;
    response.end()
  }
}).listen(8080);

였λ₯˜μ— κ΄€ν•œ 처리

const http = require('http');

http.createServer(request, response) => {
  request.on('error', (error) => {
    console.error(error);
    response.statusCode = 400;
    response.end();
  });

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

  if (request.method === 'POST' && request.url === '/echo') {
    request.pipe(response);
  } else {
    response.statusCode = 404;
    response.end();
  }
}).listen(8080);

HTTP μš”μ²­μ„ λ‹€μŒ λ™μž‘μ΄ κ°€λŠ₯ν•˜λ‹€.

  • μš”μ²­ ν•Έλ“€λŸ¬λ‘œ HTTP μ„œλ²„μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό 생성 κ°€λŠ₯ν•˜κ³  νŠΉμ • 포트λ₯Ό μ—΄ 수 μžˆλ‹€.
  • request κ°μ²΄μ—μ„œ Header, Method, URL, Body` 데이터λ₯Ό κ°€μ Έμ˜¬ 수 μžˆλ‹€.
  • URL μ΄λ‚˜ request 객체의 기반 λ°μ΄ν„°λ‘œ λΌμš°νŒ…μ΄ κ°€λŠ₯ν•˜λ‹€.
  • request κ°μ²΄μ—μ„œ response 객체둜 데이터λ₯Ό νŒŒμ΄ν”„λ‘œ μ—°κ²° κ°€λŠ₯ν•˜λ‹€.
  • request 와 response 슀트림 λͺ¨λ‘μ—μ„œ 슀트림 였λ₯˜ μ²˜λ¦¬κ°€ κ°€λŠ₯ν•˜λ‹€.