[CS] Web Server Day-41

cptkuk91·2021년 12월 31일
0

CS

목록 보기
72/139

CORS

고도화 된 최근의 웹은 여러 곳에 있는 리소스를 활용할 필요가 생겼다.
(Cross Origin Resource Sharing)


HTTP 트랜잭션 해부

서버 생성

모든 node 웹 서버 애플리케이션은 웹 서버 객체를 만들어야 합니다. 이 때 createServer를 이용합니다.

const http = require('http');

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

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

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

요청을 실제로 처리하려면 listen 메소드가 server 객체에서 호출되어야 합니다. 대부분은 서버가 사용하고자하는 포트 번호를 listen에 전달하기만 하면 됩니다.

method, URL, Header

요청을 처리할 때, 메소드와 URL을 확인한 후 이와 관련된 적절한 작업을 실행하려고 할 것입니다.

const { method, url } = request;

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

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

클라이언트가 어떻게 헤더를 설정했는지에 관계없이 모든 헤더는 소문자로만 표현된다는 것을 기억해야 합니다.

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

요청 바디

POST, PUT 요청을 받을 때 애플리케이션에 요청 바디는 중요할 것입니다. 요청 헤더에 접근하는 것보다 바디 데이터를 받는 것이 더 어렵습니다.

request 객체는 ReadableStream 인터페이스를 구현하고 있습니다. 이벤트 리스너를 등록하거나 다른 스트림에 파이프로 연결할 수 있습니다. 스트림의 'data', 'end' 이벤트에 이벤트 리스너를 등록해서 데이터를 받을 수 있습니다.

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

let body = [];

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

오류에 대한 간단한 설명

request 객체가 ReadableStream이므로 EventEmitter이기도 하고 오류가 발생했을 때 EventEmitter처럼 동작합니다.

request 오류가 발생하면 스트림에서 'error' 이벤트가 발생하면서 오류를 전달합니다. 이벤트에 리ㅣ스너가 등록되어 있지 않다면 Node.js 프로그램을 종료시킬 수도 있는 오류를 던집니다. 따라서 'error' 리스터를 추가해야 합니다.

request.on('error', (err) => {
	console.log(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 포트로 받습니다.

Express.js

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

라우팅: 메소드와 URL에 따라 분기(Routing)하기

메소드와 URL로 분기점을 만드는 것을 라우팅(Routing)이라고 합니다.

클라이언트는 특정한 HTTP 요청 메소드(GET, POST 등) 서버의 특정 URI로 HTTP 요청을 보냅니다. 라우팅은 클라이언트의 요청에 해당하는 메소드와 Endpoint에 따라 서버가 응답하는 방법을 결정하는 것입니다.

const router = express.Router()

router.get('/lower', (req, res) =>{
  res.send(data)
})

router.post('/lower', (req, res) =>{
  // do something
})

Middleware

request에 필요한 기능을 더하거나, 문제가 발견 된 부분을 걷어내는 역할을 합니다. express의 가장 큰 장점 중 하나입니다.

자주 사용하는 미들웨어

  • 모든 요청에 대해 url이나 메소드를 확인할 때
  • POST 요청 등에 포함된 body를 구조화할 때
  • 모든 요청/응답에 CORS 헤더를 붙여야 할 때
  • 요청 헤더에 사용자 인증 정보가 담겨있는지 확인할 때

모든 요청/응답에 CORS 헤더를 붙일 때

cors 모듈을 이용해서 간단하게 처리할 수 있습니다.

const cors = requires('cors')

app.use(cors())

미들웨어 작동 원리 이해하기

작동 1단계: 모든 요청에 대해 url이나 메소드를 확인 할 때
미들웨어는 프로세스 중간에 관여하여 특정 역할을 수행합니다. 미들웨어 사이사이 로거를 삽입하여 현재 데이터를 확인하거나, 디버깅에 사용할 수 있습니다.

var express = require('express');
var app = express();

app.get('/', function(req, res, next){
	next();
})

app.listen(3000);
  • app.get: 미들웨어 함수가 적용되는 HTTP apthem
  • '/': 미들웨어 함수가 적용되는 경로(라우트)
  • function: 미들웨어 함수
  • req: 미들웨어 함수에 대한 HTTP 요청 인수
  • res: 미들웨어 함수에 대한 HTTP 응답 인수
  • next: 미들웨어 함수에 대한 콜백 인수
profile
Hello World

0개의 댓글