NestJS-拦截器

4 阅读2分钟

什么是拦截器

拦截器就是在方法执行前后绑定的额外处理逻辑。在NestJS中,拦截器需要实现NestInterceptor接口并包含interceptor方法。

graph TD
A[请求进入] --> B["Guard / Pipe 等处理"] 
B --> C["Interceptor (前置逻辑)"]
C --> D["Controller / Service (业务逻辑)"] 
D --> E["Interceptor (后置逻辑)"] 
E --> F[返回响应]

拦截器适合处理很多接口都需要,但是却不应该写在业务代码里的逻辑,例如:日志,统计耗时,统一响应格式,缓存,异常转换等

下面举一个简单的例子

//首先在main.ts中创建一个全局的拦截器
app.useGlobalInterceptors(new InterceptorInterceptor());
//创建interceptor文件夹,创建interceptor.interceptor.ts文件
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable, map } from 'rxjs';
import { Request } from 'express';

const transformBigInt = (data: any) => {
  if (typeof data === 'bigint') {
    return data.toString();
  }
  if(Array.isArray(data)){
    return data.map(transformBigInt);
  }
  if(typeof data === 'object' && data !== null){
    if(data instanceof Date){
      return data
    }
    return Object.fromEntries(Object.entries(data).map(([key, value]) => [key, transformBigInt(value)]));
  }
  return data;
};

@Injectable()
export class InterceptorInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const ctx = context.switchToHttp();
    const request = ctx.getRequest<Request>();
    return next.handle().pipe(map((data) => {
      return {
        timestmap: new Date().toISOString(),
        data: transformBigInt(data),
        path: request.url,
        message: 'success',//业务逻辑自定义
        code: 200,//业务逻辑自定义
        success: true,
      };
    }));
  }
}

我们可以把next.handle()看成一条分界线,handle()之前是前置逻辑,handle()之后是后置逻辑。
1.NestJS还可以做微服务,websocket等,因此const ctx = context.switchToHttp()明确指出我们做的是Web请求,这样拿到一个request对象。
2.通过request.url拿到当前用户访问的路径,把它放回最后的返回结果里
3.next.handle()会自动调用controller中的业务逻辑。.pipe().map(data =>)对controller返回的结果进行加工
4.无论controller返回什么结果,经过拦截器后,前端接收的数据都会变成这样

{
  "timestmap": "2026-05-06T10:40:00.000Z",
  "data": { "id": "123456789", "name": "张三" }, // 这里的 ID 已经被转成字符串了
  "path": "/api/user/info",
  "message": "success",
  "code": 200,
  "success": true
}

使用拦截器的优点:
1.自动化:不需要在每一个controller中写try...catch或者手动拼装code:200
2.健壮性:解决了BigInt可能导致接口崩溃的隐患 3.可追踪性:返回了pathtimestamp,前端可以方便的调试或者打印日志

拦截器除了针对全局之外,同样可以针对某个请求例如Get

@UseInterceptors(LoggingInterceptor)
@Get()
findAll() {}