[Express server]

hyo·2022년 8월 15일
0
post-thumbnail

Express 개요

MERN stackJavaScript 생태계에서 인기 있는 프레임워크인 MongoDB, Express, React, Node.js를 지칭하는 말이다.
이 중에서 ExpressNode.js 환경에서 웹 서버, 또는 API 서버를 제작하기 위해 사용되는 인기 있는 프레임워크이다.

Express로 구현한 서버가 Node.js HTTP 모듈로 작성한 서버와 다른 점은 다음과 같다.
->

  • 미들웨어를 추가할 수 있다.
  • 라우터를 제공한다.

express로 서버 만들기

라우팅(Routing) : 메서드와 url로 분기점을 만드는 것을 라우팅(Routing)이라고 한다.

이전에 미니노드서버 과제에서 분기(Routing)를 만들어 썻던 코드 ->
추가적인 라이브러리를 사용하지 않고 순수한 Node.js로 코드를 작성하면
->

const requestHandler = (req, res) => {
  if(req.url === '/lower') {
    if (req.method === 'GET') {
      res.end(data)
    } else if (req.method === 'POST') {
      req.on('data', (req, res) => {
        // do something ...
      })
    }
  }
}

반면에 Express는 프레임워크 자체에서 라우터 기능을 제공한다.
Express라우터를 활용하면 아래와 같이 직관적인 코드를 작성할 수 있다.
->

const router = express.Router() // express 내장 프로퍼티인 라우터() 사용

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

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

미들웨어

자동차 공장에서 컨베이어 벨트 위에 올려진 자동차의 뼈대에, 각 공정마다 부품을 추가한다.
모든 부품이 추가되면 완성된 자동차가, 어딘가 문제가 있다면 불량품이 결과물로 나오게 된다.
미들웨어(Middleware)는 자동차 공장의 공정과 비슷하다. 컨베이어 벨트 위에 올라가 있는 요청(Request)에 필요한 기능을 더하거나, 문제가 발견된 불량품을 밖으로 걷어내는 역할을 한다.
미들웨어는 express의 가장 큰 장점이라고 할 수 있다.

미들웨어를 사용하는 상황

  1. POST 요청 등에 포함된 body(payload)를 구조화할 때(쉽게 얻어내고자 할 때)
  2. 모든 요청/응답에 CORS 헤더를 붙여야 할 때
  3. 모든 요청에 대해 url이나 메서드를 확인할 때
  4. 요청 헤더에 사용자 인증 정보가 담겨있는지 확인할 때

-> 미들웨어를 이용하면 Node.js만으로 구현한 서버에서는 번거로울 수 있는 작업을 보다 쉽게 적용할 수 있다.

자주 사용하는 미들웨어

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

1. POST 요청 등에 포함된 body(payload)를 구조화할 때

Node.js로 HTTP body(payload)를 받을 때에는 Buffer를 조합해서 다소 복잡한 방식으로 body를 얻을 수 있다.
네트워크 상의 chunk를 합치고, buffer를 문자열로 변환하는 작업이 필요함.

->

// Node.js로 HTTP 요청 body를 받는 코드
let body = [];
request.on('data', (chunk) => { // data가 있을때~
  body.push(chunk); // 네트워크상의 chunk들을 합치고,
}).on('end', () => { 
  body = Buffer.concat(body).toString();
  // body 변수에는 문자열 형태로 payload가 담겨져 있다.
});

body-parser 미들웨어를 사용하면 이 과정을 간단하게 처리할 수 있다.

npm으로 body-parser를 설치
-> npm install body-parser

// body-parser 미들웨어를 이용한 코드
const bodyParser = require('body-parser');
const jsonParser = bodyParser.json();

// 생략
app.post('/users', jsonParser, function (req, res) {

})

하지만 Express v4.16.0부터는 body-parser를 따로 설치 하지 않고,
Express 내장 미들웨어인 express.json()을 사용할 수 있다.

// express.json()을 이용한 코드
const jsonParser = express.json();

// 생략
app.post('/api/users', jsonParser, function (req, res) {

})

만약 express.json() 미들웨어 사용에 에러가 나면?
express.json([options])의 options에 해결법이 있다.

위의 링크로 문서에 들어가보면 이런식으로 쓰여있다.
->

번역을 해보면 ->
req.body의 모양은 사용자 제어 입력을 기반으로 하므로 이 객체의 모든 속성과 값은 신뢰할 수 없으며 신뢰하기 전에 유효성을 검사해야 합니다. 예를 들어, req.body.foo.toString()은 여러 방식으로 실패할 수 있습니다. 예를 들어 foo가 없거나 문자열이 아닐 수 있으며, toString은 함수가 아니라 문자열 또는 기타 사용자 입력일 수 있습니다.

strict : strict 배열과 객체만 허용하거나 사용하지 않도록 설정합니다. 비활성화되면 JSON.parse가 허용하는 모든 것을 허용합니다.

이런 뜻이다.

// options에 {strict: false}를 추가 하였다.
const jsonParser = express.json({strict: false});

// 생략
app.post('/api/users', jsonParser, function (req, res) {

})

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

Node.js HTTP 모듈을 이용한 코드에 CORS 헤더를 붙이려면,
응답 객체의 wirteHead 메서드를 이용할 수 있다.
하지만 Node.js 에서는 이 메서드 등을 라우팅마다 헤더를 매번 넣어주어야 했다.
그 뿐만 아니라, OPTIONS 메서드에 대한 라우팅도 따로 구현해야한다.

// Node.js에 CORS를 적용하는 예시
const defaultCorsHeader = { // CORS 헤더 만들기
  '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
};

// 생략
if (req.method === 'OPTIONS') { // OPTIONS 메서드에 대한 라우팅
  res.writeHead(201, defaultCorsHeader); // 라우팅마다 이렇게 writeHead메서드를 이용해 CORS헤더를 넣어줘야함.
  res.end()
}

CORS 미들웨어를 사용하면 위 과정을 아주 간단하게 처리할 수 있다.

npm 으로 CORS를 설치
-> npm install cors

  1. 모든 요청에 대해 CORS 허용!
// 모든 요청에 대해 cors 허용!
const cors = require('cors');

// 생략
app.use(cors());
  1. 특정 요청에 대해 CORS 허용
// 특정 요청에 대해 CORS 허용
const cors = require('cors')

// 생략
app.get('/products/:id', cors(), function (req, res, next) {
  res.json({msg: '특정 요청에 대해 CORS 허용'})
})

3. 모든 요청에 대해 url이나 메서드를 확인할 때

미들웨어는 말 그대로 프로세스 중간에 관여하여 특정 역할을 수행하고,
수많은 미들웨어가 있지만, 단순한 미들웨어 로거(logger)를 예로 들어본다.
로거는 디버깅, 서버 관리에 도움이 되기 위해 console.log로 적절한 데이터나 정보를 출력함.
데이터가 여러 미들웨어를 거치는 동안 응답할 결과를 만들어야 한다면, 미들웨어 사이사이에 로거를 삽입하여 현재 데이터를 확인하고 디버깅에 사용할 수 있다.
이런 미들웨어는 일반적으로 아래와 같은 구성을 가진다.

->

위 그림은 endpoint가 / 이면서, 클라이언트로부터 GET 요청을 받았을때 적용되는 미들웨어이다.
파라미터 순서에 유의해야한다.

-> req(요청),res(응답),next(다음 미들웨어를 실행하는 역할)

만약 특정 endpoint가 아니라 , 모든 요청에 동일한 미들웨어를 적용하려면 어떻게 해야할까??? -> app.use() 메서드를 사용하면 된다.

->

app.use(() => {console.log('hello')}) // 이렇게 써준다면 모든 요청에 console.log('hello')가 찍혀 나오는걸 볼 수있다.

아래와 같이 작성해보면 어떨까??

const logger = (req,res,next) => {
  console.log(req.method, req.url); // req.method로 method가 뭔지 req.url로 url이 뭔지 모든 요청마다 출력됨을 적용시켜본다.
  next(); // next(); 를 안써주면 각 분기점(라우팅)에 있는 console.log()는 출력 되지않았다. 써주면 같이 그다음에 출력된다.
}

app.use(logger);

4. 요청 헤더에 사용자 인증 정보가 담겨있는지 확인할 때

우선 나중에 배울 내용이라 맛보기로 학습해본다.

아래에서 HTTP 요청에서 토큰이 있는지를 판단하여, 이미 로그인한 사용자일 경우 성공, 아닐 경우 에러를 보내는 미들웨어예제를 다뤄보자.

토큰(Token)은 주로 사용자 인증에 사용한다고 우선 알고있자.

// 토큰을 통해 로그인 여부를 확인하는 미들웨어 예시
app.use((req, res, next) => {
  // 토큰이 있는지 확인, 없으면 받아줄 수 없음.
  if(req.headers.token){
    req.isLoggedIn = true;
    next();
  } else {
    res.status(400).send('invalid user')
  }
})

위 학습 내용을 바탕으로 미니노드서버를 Express로 구현해보면 ->

const express = require('express');
const port = 3000;
const app = express();
const jsonParser = express.json({strict: false});
const cors = require('cors');

app.use(jsonParser);
app.use(cors());

const logger = (req,res,next) => {
  console.log(`http request method 는 ${req.method}이고 url은 ${req.url}이다`);
  next();
}

app.use(logger); 

app.get('/', (req,res) => {
  res.send('hi');
})
app.post('/lower', (req,res) => {
  console.log(req.body);
  res.send(JSON.stringify(req.body.toLowerCase()))
})

app.post('/upper', (req, res) => {
  console.log(req.body);
  res.send(JSON.stringify(req.body.toUpperCase()));
})

app.listen(port, () => {
  console.log('서버 열림?');
})

이것으로 express 학습을 마치겠다.

profile
개발 재밌다

0개의 댓글