NestJS 拦截器
基础语法
拦截器需实现 NestInterceptor 接口,核心方法是 intercept(context: ExecutionContext, next: CallHandler)
- ExecutionContext:执行上下文,封装请求元数据(HTTP/RPC/WebSocket 等)
- CallHandler:处理器调用器,handle() 方法返回 Observable(RxJS 流),代表处理器的执行结果。
ts
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
// 前置逻辑(请求到达处理器前执行)
console.log('请求到达处理器前触发');
// 执行处理器并处理响应流
return next.handle().pipe(
map((data) => {
// 后置逻辑(处理器返回数据后执行)
return {
code: 200,
message: 'success',
data,
};
})
);
}
}参数说明
- ExecutionContext(执行上下文)
shell
# 封装了当前请求的上下文信息,兼容 HTTP、RPC(微服务)、WebSocket 等场景,核心方法如下
方法 作用
getArgs() 获取处理器的参数列表(如 HTTP 场景的 req、res)
getHandler() 获取当前执行的处理器方法(Controller 中的方法)
getClass() 获取当前处理器所属的控制器类
switchToHttp() 切换到 HTTP 上下文,返回 HttpArgumentsHost
switchToRpc() 切换到 RPC 上下文(微服务)
switchToWs() 切换到 WebSocket 上下文
# 示例
intercept(context: ExecutionContext, next: CallHandler) {
const httpContext = context.switchToHttp();
const request = httpContext.getRequest(); # 获取 Express/Fastify 请求对象
const response = httpContext.getResponse(); # 获取响应对象
console.log('请求路径:', request.url);
return next.handle();
}- CallHandler(调用处理器)
shell
handle():返回 Observable,代表处理器的执行结果(核心);
若不调用 next.handle(),则处理器不会执行(可用于权限拦截、短路逻辑)。- RxJS 操作符
shell
# 拦截器的响应处理依赖 RxJS 操作符
map:转换响应数据;
tap:执行副作用(如日志、埋点,不修改数据);
catchError:捕获并处理异常;
delay:延迟响应;
retry:重试处理器执行。多个拦截器的执行顺序
当绑定多个拦截器时,执行顺序遵循「前置逻辑正序执行,后置逻辑倒序执行」(类似洋葱模型)
ts
// 绑定顺序:InterceptorA → InterceptorB
@UseInterceptors(InterceptorA, InterceptorB)
findAll() {}
// 执行流程:
// 1. InterceptorA 前置逻辑
// 2. InterceptorB 前置逻辑
// 3. 处理器执行
// 4. InterceptorB 后置逻辑
// 5. InterceptorA 后置逻辑异步拦截器
拦截器支持异步操作(如从数据库获取配置),只需返回 Observable 或 Promise
ts
@Injectable()
export class AsyncInterceptor implements NestInterceptor {
constructor(private readonly configService: ConfigService) {}
async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> {
// 异步获取配置
const config = await this.configService.get('app');
console.log('异步配置:', config);
return next.handle().pipe(map((data) => ({ ...data, config })));
}
}跳过拦截器
通过 ExecutionContext 动态跳过拦截器
ts
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const handler = context.getHandler();
// 检查处理器是否有 @SkipInterceptor 装饰器
if (Reflect.getMetadata('skipInterceptor', handler)) {
return next.handle(); // 跳过当前拦截器
}
// 正常处理
return next.handle().pipe(map(data => ({ code: 200, data })));
}
// 自定义装饰器
export const SkipInterceptor = () => {
return (target: any, key: string) => {
Reflect.defineMetadata('skipInterceptor', true, target, key);
};
};
// 使用
@Get('raw')
@SkipInterceptor() // 跳过拦截器
getRawData() {
return { id: 1, name: '未格式化数据' };
}