코드스테이츠 8주차 / Node.js Express Middleware

자동차 공장의 공정과 비슷한 미들웨어는 익스프레스의 핵심이다
요청과 응답의 중간에 위치해서 미들웨어라고 불린다
요청과 응답을 조작해 기능을 추가하기도 하고 나쁜 요청을 걸러내기도 한다
(컨베이어 벨트 위에 올라가 있는 request에 필요한 기능을 더하거나, 문제가 발견된 불량품을 밖으로 걷어내는 역할을 한다)

미들웨어에는 수 많은 것들이 있는데 대표적으로 Morgan, Compression, Session, Body-parser, Cookie-parser, Method-override, Cors, Multer 등이 있고 모두 npm에서 다운받아서 사용 할 수 있다

Morgan 익스프레스 프레임워크가 동작하면서 나오는 메시지들을 콘솔에 표시해줌
Compression 페이지를 압축해서 전송해줌
Session은 세션 사용할 수 있게함
Body-parser은 폼에서 전송되는 POST 값을 사용할 수 있게 함
Cookie-parser는 쿠키를 사용할 수 있게 함
Method-override는 REST API에서 PUT과 DELETE 메소드를 사용할 수 있게 함
Cors 크로스오리진(다른 도메인 간의 AJAX 요청)을 가능하게 해줌
Multer 파일업로드를 할 때 주로 쓰임

자주 사용하는 미들웨어

미들웨어를 사용하는 상황들
1 모든 요청에 대해 url이나 메소드를 확인할 때
2 POST 요청 등에 포함된 body(payload)를 구조화할 때(쉽게 얻어내고자 할 때)
3 모든 요청/응답에 CORS 헤더를 붙여야 할 때
4 요청 헤더에 사용자 인증 정보가 담겨있는지 확인할 때
미들웨어를 이용하면 node.js만으로 구현한 서버에서는 다소 번거로울 수 있는 작업을 보다 쉽게 적용할 수 있다

미들웨어는 app.use와 같이 사용된다
app.use(미들웨어)
익스프레스 서버에 미들웨어를 연결해보자

app.use에 매개변수가 req, res, next인 함수를 넣으면 된다
미들웨어는 위에서 아래로 순서대로 실행되며 요청과 응답사이에 기능을 추가할수 있다 next()는 다음 매개변수로 넘어가는 함수이고 next를 실행하지 않으면 미들웨어가 실행되지 않는다

미들웨어 실행

주소를 첫번째 인수로 넣어주지 않으면 미들웨어는 모든 요청에서 실행되고
주소를 넣어주게 되면 해당 요청에서만 실행된다
next()로 다음 요청으로 보내주던지 res.send()로 응답을 보내줘야한다

app.set('port', process.env.PORT || 3000)

// app.use() => 모든 요청에 대해서 이 미들웨어가 실행된다
app.use((req,res,next) =>{
  console.log('모든 요청에 다 실행됨')
  next()
})

app.get('/', (req, res, next) =>{
  console.log('GET, / 요청에서만 실행됨')
  next()
}),(req,res) => {
  throw new Error('에러는 에러처리 미들웨어로 감')
}

// 에러처리 미들웨어
app.use((err, req, res, next) => {
  console.log(err)
  res.status(500).send(err.message)
})

app.listen(app.get('port'),()=>{
})

case 1: 모든 요청에 대해 url이나 메소드를 확인할 때

var myLogger = function (req, res, next) {
  console.log(req.method, req.url);
  next();
};

app.use(myLogger)

// POSR /upper
// 모든 요청에 대해서 미들웨어가 로그가 찍히기 때문에
// 디버깅 할 때 편리하다 

case 2: POST 요청 등에 포함된 body(payload)를 구조화할 때

node.js로 HTTP body(payload)를 받을 때에는 Buffer를 조합해서 다소 복잡한 방식으로 body를 얻을 수 있었다

let body = [];
request.on('data', (chunk) => {
  body.push(chunk);
}).on('end', () => {
  body = Buffer.concat(body).toString();
  // body 변수에는 문자열 형태로 payload가 담겨져 있습니다.
});

body-parser 미들웨어를 사용하면 이 과정을 간단하게 처리할 수 있다
body-parser에서 다룰 수 있는 바디 형식은 json, 기본 텍스트(text), buffer 등이 있다

const jsonParser = express.json()

// 생략
app.post('/api/users', jsonParser, function (req, res) {
  // req.body에는 JSON의 형태로 payload가 담겨져 있습니다.
})

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

node.js 코드에 CORS 헤더를 붙이려면, 응답 객체의 writeHead 메소드 등을 이용하고 Access-Control-Allow-* 헤더를 매번 재정의 해줘야 했다
그리고 OPTIONS 메소드에 대한 라우팅도 따로 구현해야 한다

const defaultCorsHeader = {
  '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') {
  res.writeHead(201, defaultCorsHeader);
  res.end()
}

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

const cors = require('cors')

// 생략
app.use(cors()) // 모든 요청에 대해 CORS 허용

특정 요청에 대해서만 허용 할 수 도 있다

const cors = require('cors')

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

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

HTTP 요청에서 토큰이 있는지 여부를 판단해, 이미 로그인한 사용자일 경우 성공, 아닐 경우 에러를 보내는 미들웨어 예제
토큰(Token): 주로 사용자 인증에 사용

app.use((req, res, next) => {
  // 토큰 있니? 없으면 받아줄 수 없어!
  if(req.headers.token){
    req.isLoggedIn = true;
    next()
  } else {
    res.status(400).send('invalid user')
  }
})

로그인 없이 웹사이트에 접근을 시도했을 때, 로그인 창 등으로 되돌려 보내는 경우가 있다
서버에서는 요청에 포함된 데이터를 통해 미들웨어가 요구하는 조건에 맞지 않으면, 불량품으로 판단하고 돌려보내도록 구현할 수 있다

참고자료
익스프레스 미들웨어, 라우팅

좋은 웹페이지 즐겨찾기