728x90

1. 💡 Middleware의 개념 및 역할
미들웨어(Middleware)는 HTTP 요청이 라우트 핸들러(컨트롤러 메서드)에 도달하기 직전에, 그리고 응답이 클라이언트에 도달하기 직전에 실행되는 함수 또는 클래스입니다. NestJS는 내부적으로 Express.js의 미들웨어 개념을 그대로 사용합니다.
주요 역할
미들웨어는 모든 요청에 대한 공통적인 전처리 및 후처리 작업을 수행합니다.
- 로깅: 요청 시간, IP 주소, 요청 경로 등을 기록합니다.
- 인증/토큰 추출: 헤더에서 JWT나 API 키를 추출하여 요청 객체에 첨부하거나, 기본적인 유효성 검사를 수행합니다. (복잡한 인증/인가 로직은 Guard가 담당)
- 데이터 조작: 요청 본문(Body)이나 쿼리(Query) 데이터를 가공하거나 정규화합니다.
- CORS (Cross-Origin Resource Sharing) 설정: 응답 헤더를 조작하여 CORS 정책을 적용합니다.
2. 🏗️ Middleware 구현 방법
NestJS에서 미들웨어는 클래스 기반 또는 함수 기반으로 정의할 수 있습니다.
2.1. 클래스 기반 미들웨어 (권장)
클래스 기반 미들웨어는 @Injectable() 데코레이터를 사용하고 NestMiddleware 인터페이스를 구현해야 합니다.
// logger.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
// NestMiddleware의 use 메서드 구현
use(req: Request, res: Response, next: NextFunction) {
console.log(`[${req.method}] 요청 경로: ${req.originalUrl} - ${new Date().toISOString()}`);
// 💡 next()를 호출해야 다음 미들웨어 또는 라우트 핸들러로 제어가 넘어갑니다.
next();
}
}
728x90
2.2. 함수 기반 미들웨어 (단순 로직)
DI(의존성 주입)가 필요 없는 간단한 로직이라면 함수로도 정의할 수 있습니다.
// simple-logger.function.ts
import { Request, Response, NextFunction } from 'express';
export function simpleLogger(req: Request, res: Response, next: NextFunction) {
console.log('단순 로깅 함수 실행');
next();
}
3. 🎯 Middleware 바인딩 (라우트 적용)
미들웨어를 정의했다면, 이를 특정 라우트에 연결(바인딩)해야 합니다. 이는 해당 미들웨어를 사용하는 모듈 내에서 수행됩니다.
미들웨어를 사용하는 모듈은 NestModule 인터페이스를 구현하고 configure() 메서드를 정의해야 합니다.
// app.module.ts
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './logger.middleware';
import { UsersModule } from './users/users.module';
@Module({
imports: [UsersModule],
// ...
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
// apply(): 적용할 미들웨어 지정
// forRoutes(): 미들웨어를 적용할 경로/컨트롤러 지정
// exclude(): 미들웨어 적용에서 제외할 경로 지정
consumer
.apply(LoggerMiddleware)
.forRoutes('users') // 💡 /users로 시작하는 모든 경로에 적용
.exclude({ path: 'users/login', method: RequestMethod.POST }) // /users/login POST 요청은 제외
.forRoutes(UsersController); // 💡 특정 컨트롤러에 적용 (컨트롤러 내 모든 라우트에 적용됨)
}
}
728x90
4. 🔗 Middleware의 한계점과 파이프라인에서의 위치
- 실행 순서: 미들웨어는 NestJS 파이프라인에서 가장 먼저 실행됩니다. (Middleware → Guard → Pipe → Interceptor(요청) → Controller → Interceptor(응답) → Client)
- DI 제약: 클래스 기반 미들웨어는 @Injectable()이 가능하지만, 모듈의 configure() 메서드에서 주입받아 사용할 수 있는 방법이 복잡합니다. 따라서 인증/인가와 같이 서비스(Provider)를 주입받아야 하는 로직은 미들웨어 대신 Guard를 사용하는 것이 NestJS의 철학에 더 맞습니다.
핵심: 미들웨어는 HTTP 요청 객체(req, res)에 직접 접근하여 전역적인 환경 설정이나 Express의 기능을 사용해야 할 때 유용하며, NestJS의 핵심 DI 시스템과는 약간 거리를 두고 작동합니다.
728x90
'Nest.js를 배워보자 > 6. NestJS Middleware , Guard , Intercept' 카테고리의 다른 글
| Custom Pipe 만들기 (0) | 2025.12.02 |
|---|---|
| Interceptor (인터셉터): 로깅, 응답 변형, 캐싱 (0) | 2025.12.02 |
| Guard (가드): 인증/인가 처리 (0) | 2025.12.02 |