NestJS 生命周期详细对比
NestJS 的中间件、守卫、拦截器、管道、异常过滤器是核心扩展组件,遵循单一职责原则,在请求 / 响应生命周期的不同阶段发挥作用。
中间件(Middleware)
第一道关卡
- 核心定位:请求预处理的通用关卡
- 执行时机:所有组件最前置(全局 / 模块 / 路由级)
- 核心能力:修改 req/res、请求预处理、终止请求(直接返回响应)、异步处理
- 典型场景:日志记录、CORS 处理、请求限流、Cookie 解析、简单身份验证
- 编码实现:类:实现 NestMiddleware、注册:module.configure()/app.use()、无装饰器
- 关键特点:基于 Express/Koa 中间件模型,可访问 req/res/next,通用型强
- 局限性: 无法访问执行上下文元数据(如处理方法、参数),不适合权限 / 参数处理
- 设计初衷:复用 Express/Koa 生态,处理通用的请求预处理逻辑,是「请求的第一道关卡」
- 关键能力:可直接修改 req/res(如添加 req.user),也可调用 next() 放行或直接返回响应(终止请求)。
- 示例:日志中间件(记录请求方法、路径、耗时)
ts
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
const start = Date.now();
res.on('finish', () => console.log(`耗时:${Date.now() - start}ms`));
next();
}
}守卫(Guard)
第二道关卡
- 核心定位:权限控制专用组件
- 执行时机:中间件后,拦截器 / 管道前(全局 / 控制器 / 方法)
- 核心能力:判断请求是否有权限进入后续流程(返回布尔值),抛权限异常
- 典型场景:RBAC 角色权限、接口访问控制、JWT 权限校验、条件访问(如仅管理员可访问)
- 编码实现:类:实现 CanActivate、装饰器:@UseGuards()
- 关键特点:可访问 ExecutionContext(获取请求 / 路由 / 用户信息),依赖注入友好,专注权限
- 局限性: 仅做权限判断,不修改参数 / 响应,无法终止非权限类请求
- 设计初衷:专注「访问控制」,是「权限的守门人」,仅判断 “是否放行”,不做其他逻辑。
- 关键能力:通过 ExecutionContext 解析请求上下文(如 JWT 解析后的用户信息),返回 true 放行,false 或抛 UnauthorizedException 拒绝。
- 示例:角色守卫(仅管理员可访问)
ts
@Injectable()
export class RoleGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const req = context.switchToHttp().getRequest();
const user = req.user;
return user?.role === 'admin'; // 非管理员直接抛异常
}
}管道(Pipe)
第三道关卡
- 核心定位:参数验证 / 转换专用组件
- 执行时机:守卫后,控制器方法执行前(全局 / 方法 / 参数)
- 核心能力:验证参数合法性(抛异常)、转换参数类型 / 格式(如字符串转数字)
- 典型场景:DTO 数据校验(Class-validator)、路径参数转换、查询参数验证、枚举校验
- 编码实现:类:实现 PipeTransform、装饰器:@UsePipes()、内置:ValidationPipe
- 关键特点:可访问 ArgumentMetadata(参数类型 / 元数据),专注参数处理,内置管道丰富
- 局限性: 仅处理入参,无法修改响应、做权限控制
- 设计初衷:专注「参数处理」,是「数据的校验 / 转换工」,确保进入控制器的参数合法且格式正确。
- 关键能力:支持同步 / 异步处理,内置 ValidationPipe 可结合 Class-validator 实现强类型 DTO 校验。
- 示例:参数类型转换管道(字符串转数字)
ts
@Injectable()
export class ParseIntPipe implements PipeTransform {
transform(value: string, metadata: ArgumentMetadata) {
const num = parseInt(value, 10);
if (isNaN(num)) throw new BadRequestException('参数必须是数字');
return num;
}
}拦截器(Interceptor)
第四道关卡
- 核心定位:请求 / 响应切面处理(AOP)
- 执行时机:前置:守卫后 / 管道前;后置:控制器方法执行后
- 核心能力:修改请求 / 响应数据、统一响应格式、缓存响应、超时控制、方法耗时统计、异常转换
- 典型场景:统一响应包装、接口缓存、请求 / 响应日志增强、异步流处理、重试逻辑
- 编码实现:类:实现 NestInterceptor、装饰器:@UseInterceptors()
- 关键特点:支持 AOP 编程,可访问 CallHandler(执行流),异步处理友好,能修改入参 / 出参
- 局限性: 不适合参数校验(管道更专业)、早期请求终止(中间件更合适)
- 设计初衷:基于 AOP(面向切面编程),是「请求 / 响应的增强器」,可拦截执行流程并修改入参 / 出参。
- 关键能力:前置处理(修改请求参数)、后置处理(统一响应格式)、异常捕获(转换异常)、流控制(缓存、超时)。
- 示例:统一响应格式拦截器
ts
@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(map((data) => ({ code: 200, data, message: 'success' })));
}
}异常过滤器(Exception Filter)
第五道关卡
- 核心定位:异常捕获 / 统一处理专用组件
- 执行时机:任意阶段抛异常时(最后一道异常处理)
- 核心能力:捕获特定异常、自定义响应格式、区分环境异常、记录异常日志
- 典型场景:自定义 HTTP 异常响应、业务异常处理、开发 / 生产环境异常差异化返回、异常日志
- 编码实现:类:实现 ExceptionFilter、装饰器:@UseFilters()、内置:HttpExceptionFilter
- 关键特点:可访问 ArgumentsHost(获取 req/res),支持捕获特定异常类型,依赖注入友好
- 局限性: 仅处理异常,无法参与正常请求流程
- 设计初衷:专注「异常处理」,是「异常的最终处理器」,统一捕获并格式化异常响应。
- 关键能力:可捕获特定类型异常(如业务异常、HTTP 异常),区分开发 / 生产环境返回不同信息。
- 示例:自定义业务异常过滤器
ts
@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(map((data) => ({ code: 200, data, message: 'success' })));
}
}