Express 애플리케이션에서 HTTP 요청은 라우트 핸들러에 도달하기 전에 여러 함수를 순서대로 통과한다. 이 함수들을 Middleware라고 부르며, 인증·로깅·바디 파싱처럼 반복되는 횡단 관심사(cross-cutting concerns)를 처리하는 데 사용된다. Middleware를 이해하면 Express 애플리케이션의 요청 흐름 전체를 제어할 수 있다.
Middleware는 (req, res, next) 시그니처를 가진 함수다. 요청 객체(req), 응답 객체(res), 그리고 다음 Middleware로 제어를 넘기는 next 함수를 인자로 받는다.
function logger(req, res, next) {
console.log(`${req.method} ${req.url}`);
next(); // 다음 Middleware 또는 라우트 핸들러로 이동
}
next — 현재 Middleware의 실행을 마치고 스택의 다음 함수로 제어를 전달한다. 호출하지 않으면 요청이 멈춘다.
Middleware는 app.use 또는 라우트에 등록된 순서대로 실행된다.
Client Request
│
▼
┌─────────────┐
│ Middleware1 │ (logger)
└──────┬──────┘
│ next()
▼
┌─────────────┐
│ Middleware2 │ (auth)
└──────┬──────┘
│ next()
▼
┌─────────────┐
│Route Handler│ (res.send)
└─────────────┘
│
▼
Client Response
순서가 잘못되면 인증 전에 데이터가 노출되거나, 바디 파싱 전에 req.body에 접근해 undefined를 읽는 문제가 발생한다.
| 종류 | 등록 방법 | 적용 범위 |
|---|---|---|
| Application Middleware | app.use | 모든 요청 |
| Router Middleware | router.use | 특정 라우터 |
| Error Middleware | (err, req, res, next) | 에러 발생 시 |
| Built-in Middleware | express.json 등 | 선택적 |
| Third-party Middleware | npm install 후 사용 | 선택적 |
애플리케이션 전체에 적용되며 app.use로 등록한다.
const express = require('express');
const app = express();
app.use(express.json()); // Built-in: JSON 바디 파싱
app.use(express.urlencoded({ extended: true })); // Built-in: 폼 데이터 파싱
app.use((req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
next();
});
Application Middleware — app.use로 등록해 모든 라우트에 앞서 실행되는 Middleware.
특정 경로 그룹에만 Middleware를 적용하려면 express.Router를 사용한다.
const router = express.Router();
router.use((req, res, next) => {
if (!req.headers.authorization) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
});
router.get('/profile', (req, res) => res.json({ user: 'data' }));
app.use('/api', router);
Error Middleware는 인자가 4개(err, req, res, next)인 함수로, 반드시 다른 Middleware보다 나중에 등록해야 한다.
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(err.status || 500).json({ error: err.message });
});
앞선 Middleware나 라우트 핸들러에서 next(err)를 호출하면 일반 Middleware를 건너뛰고 Error Middleware로 바로 이동한다.
자주 사용하는 Third-party Middleware는 아래와 같다.
npm install morgan cors helmet
const morgan = require('morgan');
const cors = require('cors');
const helmet = require('helmet');
app.use(helmet()); // 보안 헤더 설정
app.use(cors()); // CORS 허용
app.use(morgan('combined')); // HTTP 요청 로깅
Third-party Middleware — npm 패키지로 설치해 사용하는 Middleware. 직접 구현하지 않아도 되는 공통 기능을 빠르게 적용할 수 있다.