什么是拦截器
拦截器就是在方法执行前后绑定的额外处理逻辑。在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.可追踪性:返回了path和timestamp,前端可以方便的调试或者打印日志
拦截器除了针对全局之外,同样可以针对某个请求例如Get
@UseInterceptors(LoggingInterceptor)
@Get()
findAll() {}