欢迎来到 NestJS 系列!本文我们将深入探讨 拦截器(Interceptors),这是 NestJS 中一个强大的功能,允许你在请求处理流程的特定阶段添加逻辑。
什么是拦截器?
拦截器是实现了 NestInterceptor
接口的类,使用 @Injectable()
装饰器标记。它们能让你:
- 在方法执行前/后添加额外逻辑。
- 转换方法的返回结果。
- 修改方法的异常行为。
- 扩展基本方法的行为。
拦截器基于面向切面编程(AOP),非常适合处理横切关注点(如日志记录、缓存、性能监控等)。
创建拦截器
让我们通过一个例子创建一个简单的拦截器,用于记录请求的耗时:
typescript
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
console.log('Before...');
const start = Date.now();
return next
.handle()
.pipe(
tap(() => console.log(`After... ${Date.now() - start}ms`)),
);
}
}
代码解析:
intercept()
方法接收ExecutionContext
(类似Guard
中的上下文)和CallHandler
。CallHandler
的handle()
方法返回一个 RxJSObservable
,表示路由处理程序的响应流。- 使用
tap()
操作符添加响应后的逻辑(记录耗时)。
绑定拦截器
拦截器可以绑定到以下位置:
- 控制器级别:影响所有路由。
- 方法级别:仅影响特定路由。
- 全局级别:影响所有路由。
控制器/方法级别
使用 @UseInterceptors()
装饰器:
typescript
@Controller('users')
@UseInterceptors(LoggingInterceptor)
export class UsersController {
@Get()
@UseInterceptors(LoggingInterceptor)
findAll() {
return [];
}
}
全局级别
在 main.ts
中注册:
typescript
const app = await NestFactory.create(AppModule);
app.useGlobalInterceptors(new LoggingInterceptor());
拦截器的实际应用
1. 统一响应格式
拦截器可以标准化所有响应的结构:
typescript
import { map } from 'rxjs/operators';
@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
map(data => ({
success: true,
result: data,
timestamp: new Date().toISOString(),
})),
);
}
}
2. 记录请求日志
记录请求的详细信息:
typescript
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest();
console.log(`Request to ${request.url} | Method: ${request.method}`);
return next.handle();
}
}
3. 处理超时
使用 RxJS 的 timeout
操作符设置超时:
typescript
import { timeout } from 'rxjs/operators';
@Injectable()
export class TimeoutInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
timeout(5000), // 5秒超时
);
}
}
总结
拦截器是 NestJS 中处理横切关注点的优雅方式。通过本文,你学会了:
- 如何创建自定义拦截器。
- 如何将拦截器绑定到不同作用域。
- 如何利用拦截器实现日志、响应转换和超时处理。
在下一篇文章中,我们将探讨 自定义装饰器(Custom Decorators)。敬请关注!