커스텀 미들웨어 만들기


조현영님의 Node.js 교과서의 내용을 공부하여 정리한 내용입니다.


6.3.1 커스텀 미들웨어 만들기

  • 직접 미들웨어를 만들어보면서 미들웨어의 원리를 이해보자.
  • 요청이 들어올 때 콘솔에 메시지를 찍는 단순한 미들웨어이다.
  • logger보다 위에 다음 코드를 적어준다.
1
2
3
4
5
6
7
8
9
10
11
// app.js
// ...
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "pug");

app.use(function(req, res, next) {
console.log(req.url, "저도 미들웨어입니다");
next();
});
app.use(logger("dev"));
// ...
  • app.js 파일을 저장하고 서버를 실행한다.
1
$ npm start
1
2
3
4
/ 저도 미들웨어입니다
GET / 200 416.849 ms – 170
/stylesheets/style.css 저도 미들웨어입니다
GET /stylesheets/style.css 200 10.119 ms - 111
  • 요청 두 개, 즉 GET /와 GET /stylesheets/style.css가 서버로 전달되었다.
  • 각각의 요청이 모두 방금 만든 커스텀 미들웨어를 작동시켰다.
  • 이렇게 서버가 받은 요청은 미들웨어를 타고 라우터까지 전달된다.

주의해야 할 점!

  • 반드시 미들웨어 안에서 next()를 호출해야 다음 미들웨어로 넘어간다.
  • logger나 express.json, express.urlencoded, cookieParser, express.static - 모두 내부적으로는 next()를 호출하므로 다음 미들웨어로 넘어갈 수 있다.
  • next()는 미들웨어의 흐름을 제어하는 핵심적인 함수이다.

next 함수의 다른 기능

  • 인자의 종류로 기능이 구분된
  • 인자를 아무것도 넣지 않으면 단순하게 다음 미들웨어로 넘어간다.
  • next 함수의 인자로 route를 넣으면 특수한 기능을 한다.
  • 이것은 라우터를 배울 때 함께 알아볼 예정
  • route 외의 다른 값을 넣으면 다른 미들웨어나 라우터를 건너 뛰고 바로 에러 핸들러로 이동
  • 넣어준 값은 에러에 대한 내용으로 간주됨

에러 핸들링 미들웨어

404 처리 미들웨어

익스프레스가 생성해주는 에러 핸들링 미들웨어를 보면 이해하기 쉽다.

  • 가장 흔한 에러가 404 에러이다.
  • 라우터에 등록되지 않은 주소로 요청이 들어올 때 발생
  • 이 경우에는 404 NOT FOUND 상태 코드를 응답해주어야 한다.
1
2
3
4
// 404 처리 미들웨어
app.use(function(req, res, next) {
next(createError(404));
});
  • 라우터 다음에 나오는 이 부분이 404 에러를 만들어내는 미들웨어
  • 라우터에서 요청이 처리되지 않으면(일치하는 주소가 없다면) 요청은 라우터 다음에 위치한 이 미들웨어로 오게 된다.
  • http-errors(createError) 패키지가 404 에러를 만들어내고, 이 에러를 next에 담아 에러 핸들러로 보내고 있다.

에러 핸들러

  • 에러 핸들링 미들웨어는 아래와 같다.
1
2
3
4
5
6
7
8
// 에러 핸들러
app.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};

res.status(err.status || 500);
res.render("error");
});
  • 이 미들웨어의 내용은 템플릿 엔진을 다룰 때 배울 예정
  • 다른 미들웨어와 다르게 함수의 매개변수가 4개
  • req 전에 err라는 매개변수가 추가됨
  • next 함수에 넣어준 인자가 err 매개변수로 연결된다.
  • 에러 핸들링 미들웨어는 일반적으로 미들웨어 중 제일 아래에 위치하여 위에 있는 미들웨어에서 발생하는 에러를 받아서 처리한다.

app.use의 응용 방법

  • 하나의 use에 미들웨어를 여러 개 장착할 수 있다.
  • 순서대로 실행된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
app.use(
"/",
function(req, res, next) {
console.log("첫 번째 미들웨어");
next();
},
function(req, res, next) {
console.log("두 번째 미들웨어");
next();
},
function(req, res, next) {
console.log("세 번째 미들웨어");
next();
}
);
  • 이 성질을 활용하여 Express-generator가 생성한 코드도 다음과 같이 줄일 수 있다.
1
2
3
4
5
6
7
app.use(
logger("dev"),
express.json(),
express.urlencoded({ extended: false }),
cookieParser(),
express.static(path.join(__dirname, "public"))
);
  • 가독성이 좋지 않아 이렇게는 잘 사용하지 않지만, 유효한 코드이다.

  • next를 호출하지 않으면 다음 미들웨어로 넘어가지 않는다는 성질을 사용하여 다음과 같은 미들웨어도 만들 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
app.use(
function(req, res, next) {
if (+new Date() % 2 === 0) {
return res.status(404).send("50% 실패");
} else {
next();
}
},
function(req, res, next) {
console.log("50% 성공");
next();
}
);
  • 50% 확률(숫자를 2로 나눈 나머지가 항상 1이거나 0임을 이용)로 404 Not Found를 응답하거나 다음 미들웨어로 넘어가는 미들웨어
  • 이 미들웨어 자체는 크게 의미가 없지만, 나중에 로그인한 사용자인지 확인할 때 위의 코드를 응용하게 된다.

다음 시간에는 Express에 사용되는 다른 미들웨어에 대해서도 알아보자.