Skip to content

NestJS 生命周期详细对比

NestJS 的中间件、守卫、拦截器、管道、异常过滤器是核心扩展组件,遵循单一职责原则,在请求 / 响应生命周期的不同阶段发挥作用。

中间件(Middleware)

第一道关卡

  1. 核心定位:请求预处理的通用关卡
  2. 执行时机:所有组件最前置(全局 / 模块 / 路由级)
  3. 核心能力:修改 req/res、请求预处理、终止请求(直接返回响应)、异步处理
  4. 典型场景:日志记录、CORS 处理、请求限流、Cookie 解析、简单身份验证
  5. 编码实现:类:实现 NestMiddleware、注册:module.configure()/app.use()、无装饰器
  6. 关键特点:基于 Express/Koa 中间件模型,可访问 req/res/next,通用型强
  7. 局限性: 无法访问执行上下文元数据(如处理方法、参数),不适合权限 / 参数处理
  8. 设计初衷:复用 Express/Koa 生态,处理通用的请求预处理逻辑,是「请求的第一道关卡」
  9. 关键能力:可直接修改 req/res(如添加 req.user),也可调用 next() 放行或直接返回响应(终止请求)。
  10. 示例:日志中间件(记录请求方法、路径、耗时)
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)

第二道关卡

  1. 核心定位:权限控制专用组件
  2. 执行时机:中间件后,拦截器 / 管道前(全局 / 控制器 / 方法)
  3. 核心能力:判断请求是否有权限进入后续流程(返回布尔值),抛权限异常
  4. 典型场景:RBAC 角色权限、接口访问控制、JWT 权限校验、条件访问(如仅管理员可访问)
  5. 编码实现:类:实现 CanActivate、装饰器:@UseGuards()
  6. 关键特点:可访问 ExecutionContext(获取请求 / 路由 / 用户信息),依赖注入友好,专注权限
  7. 局限性: 仅做权限判断,不修改参数 / 响应,无法终止非权限类请求
  8. 设计初衷:专注「访问控制」,是「权限的守门人」,仅判断 “是否放行”,不做其他逻辑。
  9. 关键能力:通过 ExecutionContext 解析请求上下文(如 JWT 解析后的用户信息),返回 true 放行,false 或抛 UnauthorizedException 拒绝。
  10. 示例:角色守卫(仅管理员可访问)
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)

第三道关卡

  1. 核心定位:参数验证 / 转换专用组件
  2. 执行时机:守卫后,控制器方法执行前(全局 / 方法 / 参数)
  3. 核心能力:验证参数合法性(抛异常)、转换参数类型 / 格式(如字符串转数字)
  4. 典型场景:DTO 数据校验(Class-validator)、路径参数转换、查询参数验证、枚举校验
  5. 编码实现:类:实现 PipeTransform、装饰器:@UsePipes()、内置:ValidationPipe
  6. 关键特点:可访问 ArgumentMetadata(参数类型 / 元数据),专注参数处理,内置管道丰富
  7. 局限性: 仅处理入参,无法修改响应、做权限控制
  8. 设计初衷:专注「参数处理」,是「数据的校验 / 转换工」,确保进入控制器的参数合法且格式正确。
  9. 关键能力:支持同步 / 异步处理,内置 ValidationPipe 可结合 Class-validator 实现强类型 DTO 校验。
  10. 示例:参数类型转换管道(字符串转数字)
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)

第四道关卡

  1. 核心定位:请求 / 响应切面处理(AOP)
  2. 执行时机:前置:守卫后 / 管道前;后置:控制器方法执行后
  3. 核心能力:修改请求 / 响应数据、统一响应格式、缓存响应、超时控制、方法耗时统计、异常转换
  4. 典型场景:统一响应包装、接口缓存、请求 / 响应日志增强、异步流处理、重试逻辑
  5. 编码实现:类:实现 NestInterceptor、装饰器:@UseInterceptors()
  6. 关键特点:支持 AOP 编程,可访问 CallHandler(执行流),异步处理友好,能修改入参 / 出参
  7. 局限性: 不适合参数校验(管道更专业)、早期请求终止(中间件更合适)
  8. 设计初衷:基于 AOP(面向切面编程),是「请求 / 响应的增强器」,可拦截执行流程并修改入参 / 出参。
  9. 关键能力:前置处理(修改请求参数)、后置处理(统一响应格式)、异常捕获(转换异常)、流控制(缓存、超时)。
  10. 示例:统一响应格式拦截器
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)

第五道关卡

  1. 核心定位:异常捕获 / 统一处理专用组件
  2. 执行时机:任意阶段抛异常时(最后一道异常处理)
  3. 核心能力:捕获特定异常、自定义响应格式、区分环境异常、记录异常日志
  4. 典型场景:自定义 HTTP 异常响应、业务异常处理、开发 / 生产环境异常差异化返回、异常日志
  5. 编码实现:类:实现 ExceptionFilter、装饰器:@UseFilters()、内置:HttpExceptionFilter
  6. 关键特点:可访问 ArgumentsHost(获取 req/res),支持捕获特定异常类型,依赖注入友好
  7. 局限性: 仅处理异常,无法参与正常请求流程
  8. 设计初衷:专注「异常处理」,是「异常的最终处理器」,统一捕获并格式化异常响应。
  9. 关键能力:可捕获特定类型异常(如业务异常、HTTP 异常),区分开发 / 生产环境返回不同信息。
  10. 示例:自定义业务异常过滤器
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' })));
  }
}