본문 바로가기
Study/Express(node.js)

express ) 미들웨어

by JongIk 2022. 2. 4.
반응형

미들웨어

 

express ) Router

라우팅이란 ? 처리 로직을 따로 관리해 사용자가 접속한 URL 과 method 에 따라 해당 록직을 실행하는 것입니다. 라우팅 등록 먼저 express 를 설치합니다. npm install -s express express 에서는 라우팅을 직

jongik.tistory.com

앞의 글에서 Router() 를 이용해 모듈 형태로 생성된 라우터를 app.use 로 등록하여 사용했습니다. app.use 가 미들웨어를 등록하는 부분입니다.
또한, app.use(bodyParse()) 를 이용해 클라이언트가 body 에 포함한 데이터를 사용 가능하도록 파싱합니다. app.use 로 등록한 미들웨어는 모든 요청에 대해 동작하게 됩니다.

하지만 사용자 요청을 처리하기 위해 사용한 app.get, app.post, app.put, app.delete 등의 미들웨어는 요청 URL 과 method 에 따라 동작하는 미들웨어입니다.
우리가 사용자 요청을 처리하기 위해 라우팅을 한 부분 모두가 미들웨어를 등록한 과정이라고 할 수 있습니다.

사용자 요청을 라우팅하기 위해 콜백함수를 등록하는데, app.use 에 등록하는 미들웨어 또한 같은 형태로 콜백함수를 받습니다. 첫 번째 인자는 요청 객체, 두 번째 인자는 응답 객체, 세 번째 인자는 next 입니다.
미들웨어에서는 next 가 매우 중요합니다.


미들웨어 등록하기

app.use 를 이용해 모든 요청에 대해 처리하는 미들웨어를 등록할 수 있습니다.

const express = require('express');
let app = express();

const http = require('http');

app.use((req, res, next) => {  // 미들웨어 등록
  console.log('첫 째 미들웨어';
  next()
})

app.get('/', (req, res, next) => {   // 미들웨어 등록
  res.send('hello world');
})

http.createServer(app).listen(3000, () => {
  console.log('server on : 3000 PORT');
})

localhost:3000 으로 접속했을 시 결과

위 코드를 조금 더 자세히 살펴보겠습니다.

첫 번째 미들웨어

app.use((req, res, next) => {  // 미들웨어 등록
  console.log('첫 째 미들웨어';
  next()
})
  • 위 미들웨어는 app.use 로 등록했기 때문에 모든 요청에 대해 실행됩니다.
  • console.log() 를 실행 후 다음 미들웨어를 호출합니다. 만약 next() 가 없다면 서버 측에만 첫 번째 미들웨어가 출력되고 클라이언트는 아무런 응답을 받지 못하게 됩니다.
  • 만약 해당 미들웨어가 실행 중 문제가 발생하여 다음 미들웨어를 실행하지 못한다면 해당 부분에서 두 번째 인자인 응답 객체를 이용하여 클라이언트에게 응답을 해주어야 합니다.
  • 미들웨어에서는 반드시 next() 를 호출해 다음 미들웨어를 호출해야하며, 만약 문제가 발생했다면 클라이언트에게 문제가 발생했다고 알려야 합니다.

두 번째 미들웨어

app.get('/', (req, res, next) => {   // 미들웨어 등록
  res.send('hello world');
})
  • 이 부분은 모든 요청에 따라 실행되지 않고 요청된 method 와 URL 에 따라 실행되는 부분입니다.
  • 여기에서는 굳이 next() 를 이용해 다음 미들웨어를 호출할 필요가 없습니다. 원하는 최종 로직의 코드를 다 실행했기 때문입니다.

함수 형태로 분리한 미들웨어

미들웨어도 복잡한 로직을 가질 수 있기 때문에 이럴 때는 함수 형태로 분리해 등록할 수 있습니다. 앞의 글에서 bodyParse() 를 등록했던 것처럼 함수 형태로 등록 가능합니다.

const express = require('express');
let app = express();

const http = require('http');

let firstMiddleware = (req, res, next) => {
  console.log('첫 번째 미들웨어');
    next();
}

app.use(firstMiddleware);

app.get('/', (req, res, next) => {
  res.send('hello world');
})

http.createServer(app).listen(3000, () => {
  console.log('server on : 3000 PORT');
})
  • 위 코드는 처음 미들웨어를 등록했을 때와 동일하게 작동하는 코드입니다.

라우터에서 미들웨어 등록하기

라우터에서 미들웨어를 추가로 만들 수 있습니다.
다수의 API 가 있을 때 특정 API 만 실행하고 싶은 미들웨어가 있다면 다음과 같은 방법으로 미들웨어를 추가하면 됩니다. next() 가 다음 미들웨어를 호출한다는 개념이 중요합니다.

const express = require('express');
let app = express();

const http = require('http');

let firstMiddleware = (req, res, next) => {
  console.log('첫 번째 미들웨어');
    next();
}

app.get('/', firstMiddleware, (req, res, next) => {
    res.send('hello world111');
});

app.get('/user', (req, res, next) => {
  res.send('hello world222');
})

http.createServer(app).listen(3000, () => {
  console.log('server on : 3000 PORT');
})
  • 2 개의 API 가 있으며 '/' GET 요청에만 미들웨어가 추가되었습니다.
  • app.get('/', 미들웨어, 미들웨어...) 형태로 계속 등록이 가능하며 post, put, delete, use 모두 사용 가능합니다.
  • 단, next 를 통해서 다음 미들웨어를 제대로 호출해야 합니다.

미들웨어를 활용한 에러 처리

에러를 처리하는 미들웨어는 약간 특수한 형태로 이루어져 있습니다. 지금까지 미들웨어는 첫 번째 인자로 요청 객체, 두 번째 인자로 응답 객체, 세 번째 인자로는 next 객체를 받았습니다.

하지만 에러를 처리하는 미들웨어는 첫 번째 에러 객체를 받습니다. 그리고 두 번째 객체부터 네 번째 객체까지 요청, 응답, next 순서로 객체를 받게 됩니다.

app.use((err, req, res, next) => {
  console.log(err);
})

에러 처리를 위한 미들웨어는 단순히 next 를 호출하면 됩니다.
이때, next() 를 실행하면서 인자를 넘겨 주어야합니다.

미들웨어를 이용한 에러 처리

const express = require('express');
let app = express();

const http = require('http');

app.get('/:id', (req, res, next) => {
    let id = req.params.id;
    if (id == 1) {
        next('error 발생');
    } else {
        res.send('hello world');
    }
});

app.use((err, req, res, next) => {
    console.log(err);
    res.status(500).send(err)
})

http.createServer(app).listen(3000, () => {
    console.log('server on: 3000 PORT')
});
  • id 값이 1 일 때 next('error occured') 가 실행되면 app.use((err,req,res,next)) 를 실행합니다.
  • 에러 미들웨어의 첫 번째 인자인 에러 객체는 next() 로 전달한 첫 번째 인자를 받게 됩니다.

404 처리하기

가장 마지막에 있는 에러 처리 미들웨어 바로 위에 미들웨어를 추가하면 404 에러를 간단하게 처리할 수 있습니다.

// 생략
app.use((req, res, next) => { // 404 처리 미들웨어
  console.log('404');
  res.status(404).send('<h1>not found page</h1>');
});

app.use((err, req, res, next) => {
    console.log(err);
    res.status(500).send(err)
})
// 생략
  • 등록한 라우터에서 일치하는 method 와 URL 이 있었다면 next 가 없기 때문에 404를 처리하는 미들웨어가 실행되지 않습니다.
  • 하지만 일치하는 라우터가 없기 때문에 404를 처리하는 미들웨어가 실행됩니다.

정리

미들웨어에서 중요한 부분은 등록한 순서로 미들웨어를 실행한다는 것입니다.
대신, 다음 미들웨어를 실행하기 위해서는 next() 를 호출해야합니다. 그리고 에러를 처리하는 미들웨어는 특수하게 4개의 인자를 받으며 해당 미들웨어를 실행하기 위해서는 next() 에 첫 번째 인자를 넣어서 호출하면 됩니다.


express 에서 제공하는 미들웨어

모든 미들웨어를 직접 만들어 사용하진 않습니다.
대부분의 미들웨어를 express 에서 제공하기 때문에 npm install -s [모듈명] 으로 설치한 다음 사용하면 됩니다.

morgan

morgan 은 클라이언트의 요청 로그를 확인하는 미들웨어입니다.
200은 녹색, 404는 황색, 500 은 적색으로 표시되어 로그를 한 눈에 보기 편리합니다.

const logger = require('morgan');
app.use(logger('dev'));

body-parser

클라이언트가 body 에 포함한 데이터를 파싱하기 위해 필요한 미들웨어입니다.

const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false}));
app.use(bodyParser.json());

bodyParser 를 제대로 사용하기 위해서는 bodyParser.json() 의 형태로 호출해야합니다.
body 에는 데이터의 제한이 없지만 node.js 에서는 100Kb 로 제한이 걸려있습니다. 하지만 json() 에 옵션을 추가해 제한을 변경할 수 있습니다.

app.use(bodyParser.json({limit:5000000})); // 5Mb 까지 제한 해제

cookie-parser

헤더에 포함한 쿠키를 JSON 형태로 파싱하는 미들웨어입니다.

const cookieParser = require('cookie-parser');
app.use(cookieParser());

multer

multer 는 파일 업로드를 위한 미들웨어입니다.

express.static

정적파일 제공을 위한 미들웨어입니다.
express 는 CSS, JS, images 파일같은 정적 파일을 하나의 디렉토리에서 관리합니다.

passport

사용자 인증을 위한 미들웨어로 passport 를 이용하면 페이스북, 네이버에서 제공하는 인증시스템을 이용할 수 있으며 인증시스템을 직접 만드는 것도 가능합니다.


미들웨어 (라우터) 에서 주의할 점

하나의 미들웨어 (라우터) 에서 응답이 여러 번 등장하면 안됩니다.

만약

app.get('/', (req, res, next) =>{
  //next() => 응답과 같이 실행되면 에러 발생
  res.send('hello world1');
  res.send('hello world2');
})

이런 형태로 만들어진 API 를 생성한다면 다음과 같은 에러가 발생하게 됩니다.

Error: Can't set headers after they are sent'

응답뿐만 아니라 next 와 응답을 같이 사용하는 경우도 마찬가지로 똑같은 에러가 발생하게 됩니다.

이 경우에는 조건분기를 이용해 next 와 응답하는 부분을 함께 사용할 수 있습니다.

app.get('/', (req, res, next) =>{
    if(조건){
      next();
    }else{
      res.send('hello world');
    }
})

참고도서 : 자바스크립트로 서버와 클라이언트 구축하기

반응형

댓글