
미들웨어의 동작 원리
미들웨어는 파이프라인처럼 작동한다. 요청이 들어오면 Express는 이를 일련의 미들웨어 함수들을 통해 순차적으로 전달하는데, 각 미들웨어는 요청을 검사하고 필요한 처리를 수행한 후, 다음 미들웨어로 전달할지 결정한다.
app.use((req, res, next) => {
console.log('첫 번째 미들웨어');
// 요청 객체에 새로운 속성 추가
req.customData = '이 데이터는 다음 미들웨어에서 사용할 수 있습니다';
next();
});
app.use((req, res, next) => {
console.log('두 번째 미들웨어');
console.log(req.customData); // 이전 미들웨어에서 추가한 데이터 접근 가능
next();
});미들웨어 체인의 내부 구현
Express는 내부적으로 미들웨어 함수들을 배열로 관리한다. 각 요청은 배열의 첫 번째 미들웨어부터 순차적으로 실행되며, next()가 호출되면 배열의 다음 미들웨어로 제어를 넘긴다. 이를 간단히 구현하면 다음과 같다.
class Express {
constructor() {
this.middlewares = [];
}
use(path, handler) {
if (typeof path === 'function') {
handler = path;
path = '/';
}
this.middlewares.push({ path, handler });
}
handle(req, res) {
let index = 0;
const next = () => {
let layer = this.middlewares[index++];
if (!layer) return;
// 경로 매칭 확인
if (req.url.startsWith(layer.path)) {
layer.handler(req, res, next);
} else {
next();
}
};
next();
}
}- middlewares 배열에 미들웨어를 순서대로 저장한다.
- next 함수는 다음 미들웨어로 제어를 넘긴다.
- 각 미들웨어는
req.url이 자신의 경로와 일치할 때만 실행된다. - 경로에 맞지 않으면
next()를 호출해 다음 미들웨어로 넘어간다.
라우팅 시스템의 동작 방식
라우팅은 요청의 경로와 HTTP 메서드를 기반으로 적절한 핸들러 함수를 찾아 실행하는 구조다.
const router = express.Router();
router.get('/users', (req, res) => {
res.send('User list');
});내부적으로 Express 라우터는 다음과 같은 방식으로 라우팅 정보를 관리한다.
const routes = {
GET: new Map(),
POST: new Map(),
PUT: new Map(),
DELETE: new Map()
};
// 예시: 라우트 등록
routes.GET.set('/users', handler);
// 요청 처리
const handleRequest = (method, url) => {
const handler = routes[method]?.get(url);
if (handler) {
handler(req, res);
} else {
res.statusCode = 404;
res.end('Not Found');
}
};이 구조를 통해 HTTP 메서드와 경로가 일치하는 핸들러를 찾아 실행하게 된다.
요약
- 미들웨어는 Express의 핵심으로, 요청과 응답을 가공하고 처리하는 함수들의 체인이다.
next()를 통해 다음 단계로 제어를 넘길 수 있다. - Express는 미들웨어를 배열로 관리하고, 요청 경로와 일치하는 미들웨어만 실행한다.
- 라우팅 시스템은 요청의 HTTP 메서드와 경로를 기준으로 핸들러를 실행하는 구조를 가진다.
이 글은 Udemy의 【한글자막】 NodeJS 완벽 가이드 : MVC, REST APIs, GraphQL, Deno 강의를 토대로 공부한 내용을 정리한 것입니다.