Skip to content

请求生命周期概览

一、完整链路

HTTP 请求到达


  Middleware(中间件)
      │  Express/Fastify 级别
      │  可修改 req/res,调用 next()
      │  无法访问 NestJS 路由元数据

  Guard(守卫)
      │  返回 true/false 决定是否放行
      │  可访问路由元数据(@Roles 等装饰器)
      │  返回 false → 自动抛出 403 ForbiddenException

  Interceptor(拦截器)—— 进入阶段
      │  基于 RxJS,在 Handler 前后均可插入逻辑
      │  日志、耗时统计、缓存、响应转换

  Pipe(管道)
      │  转换和校验参数(DTO 验证、类型转换)
      │  抛出 BadRequestException → 跳过 Handler

  Handler(控制器方法)
      │  业务逻辑处理
      │  抛出异常 → 跳过 Interceptor 返回阶段

  Interceptor(拦截器)—— 返回阶段
      │  统一包装响应格式、序列化

  ExceptionFilter(异常过滤器)
      │  捕获整个链路中抛出的所有异常
      │  统一格式化错误响应

  HTTP 响应返回

二、每个环节的职责边界

环节执行时机核心能力典型用途
MiddlewareGuard 之前访问原始 req/res日志、CORS、压缩、限流
GuardPipe 之前读取路由元数据、决定放行认证(JWT 验证)、授权(角色检查)
Interceptor(进入)Handler 之前包装 Observable、读上下文耗时开始、缓存命中检测
PipeHandler 参数绑定时转换/验证参数值DTO 验证、类型转换、参数清洗
Handler业务逻辑调用 Service、返回数据
Interceptor(返回)Handler 之后变换 Observable 结果统一响应格式、序列化
ExceptionFilter抛出异常时捕获任何异常统一错误格式、记录错误日志

三、如何选择用哪个环节

场景判断树:

需要修改原始 req/res 对象(如添加 traceId)?
  → Middleware

需要读取路由装饰器上的元数据(@Roles、@Public 等)?
  → Guard(守卫)或 Interceptor(不能是 Middleware)

需要在 Handler 执行前拦截并可能阻止执行?
  → Guard(返回 false)或 Pipe(抛出异常)

需要转换或验证 Handler 的输入参数?
  → Pipe

需要包装 Handler 的返回值?
  → Interceptor(返回阶段 map 操作符)

需要在执行前后都有逻辑(如计时)?
  → Interceptor(进入 + 返回两个阶段)

需要统一处理异常?
  → ExceptionFilter

需要同时保护多个路由(认证)?
  → Guard(全局注册)

按常见需求对照:

需求推荐环节原因
记录请求日志Middleware需要在路由解析前就记录
CORS / 请求压缩MiddlewareExpress/Fastify 级别处理
JWT Token 验证Guard需要读取路由 @Public() 装饰器
角色权限检查Guard需要读取 @Roles() 装饰器
接口耗时统计Interceptor需要包裹整个 Handler 执行
统一响应格式 {code, data, message}Interceptormap 转换返回值
响应缓存Interceptor可短路 Handler,直接返回
DTO 校验(字段格式、必填)PipeValidationPipe + class-validator
路径参数转 numberPipeParseIntPipe
统一错误响应格式ExceptionFilter捕获所有未处理异常

四、绑定范围与优先级

每种机制都支持三个层级绑定,执行顺序:全局 → 控制器 → 路由

typescript
// 1. 全局(main.ts)— 作用于所有路由
app.useGlobalGuards(new JwtAuthGuard());
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
app.useGlobalInterceptors(new ResponseInterceptor());
app.useGlobalFilters(new AllExceptionsFilter());

// 全局注册的缺点:无法注入 NestJS Provider(如 Reflector)
// 解决:通过 APP_GUARD 等令牌注册(可以注入依赖)
providers: [
  { provide: APP_GUARD, useClass: JwtAuthGuard },
  { provide: APP_INTERCEPTOR, useClass: ResponseInterceptor },
  { provide: APP_PIPE, useClass: ValidationPipe },
  { provide: APP_FILTER, useClass: AllExceptionsFilter },
]

// 2. 控制器级别
@UseGuards(JwtAuthGuard)
@UseInterceptors(LoggingInterceptor)
@Controller('users')
export class UsersController {}

// 3. 路由级别
@UseGuards(RolesGuard)
@UseFilters(HttpExceptionFilter)
@Get(':id')
findOne(@Param('id') id: string) {}

同一层级多个绑定时,按声明顺序(从左到右/从上到下)执行:

typescript
@UseGuards(AuthGuard, RolesGuard)
// AuthGuard 先执行,通过后 RolesGuard 再执行

五、异常传播规则

异常在链路中的传播:

Handler 抛出 NotFoundException

  跳过 Interceptor 返回阶段(pipe 操作符)

  被 ExceptionFilter 捕获

  返回 404 响应

Guard 抛出/返回 false

  跳过 Interceptor 进入阶段后的所有环节

  被 ExceptionFilter 捕获(ForbiddenException)

Interceptor 进入阶段抛出异常

  跳过 Handler

  被 ExceptionFilter 捕获

六、调试技巧:追踪请求经过的每个环节

typescript
// 在每个环节打印日志,验证执行顺序
@Injectable()
export class DebugGuard implements CanActivate {
  canActivate() {
    console.log('[Guard] 执行');
    return true;
  }
}

@Injectable()
export class DebugInterceptor implements NestInterceptor {
  intercept(ctx: ExecutionContext, next: CallHandler) {
    console.log('[Interceptor] 进入');
    return next.handle().pipe(
      tap(() => console.log('[Interceptor] 返回')),
    );
  }
}
// 预期输出:
// [Middleware] 执行
// [Guard] 执行
// [Interceptor] 进入
// [Handler] 执行
// [Interceptor] 返回

可运行 Demo: practice/02-request-lifecycle — Middleware/Guard/Interceptor/Pipe 全链路追踪 Demo


常见错误

错误原因解决
中间件不执行configure() 中路由写错或未 applyforRoutes('*') 先确认全局生效,再收窄范围
Guard 在中间件之前报错误解执行顺序顺序:Middleware → Guard → Interceptor → Pipe → Handler
异常过滤器捕获不到某个异常过滤器注册层级低于抛出点全局过滤器用 app.useGlobalFilters(),或在 Controller 级别注册

NestJS 深度学习体系