NestJS 系列:拦截器(Interceptors)

欢迎来到 NestJS 系列!本文我们将深入探讨 拦截器(Interceptors),这是 NestJS 中一个强大的功能,允许你在请求处理流程的特定阶段添加逻辑。


什么是拦截器?

拦截器是实现了 NestInterceptor 接口的类,使用 @Injectable() 装饰器标记。它们能让你:

  1. 在方法执行前/后添加额外逻辑。
  2. 转换方法的返回结果。
  3. 修改方法的异常行为。
  4. 扩展基本方法的行为。

拦截器基于面向切面编程(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
  • CallHandlerhandle() 方法返回一个 RxJS Observable,表示路由处理程序的响应流。
  • 使用 tap() 操作符添加响应后的逻辑(记录耗时)。

绑定拦截器

拦截器可以绑定到以下位置:

  1. 控制器级别:影响所有路由。
  2. 方法级别:仅影响特定路由。
  3. 全局级别:影响所有路由。

控制器/方法级别

使用 @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)。敬请关注!

相关推荐
Kapaseker4 分钟前
前端已死...了吗
android·前端·javascript
Moment12 分钟前
富文本编辑器技术选型,到底是 Prosemirror 还是 Tiptap 好 ❓❓❓
前端·javascript·面试
xkxnq17 分钟前
第二阶段:Vue 组件化开发(第 18天)
前端·javascript·vue.js
晓得迷路了19 分钟前
栗子前端技术周刊第 112 期 - Rspack 1.7、2025 JS 新星榜单、HTML 状态调查...
前端·javascript·html
怕浪猫21 分钟前
React从入门到出门 第五章 React Router 配置与原理初探
前端·javascript·react.js
鹏多多28 分钟前
前端2025年终总结:借着AI做大做强再创辉煌
前端·javascript
哈__31 分钟前
React Native 鸿蒙跨平台开发:Vibration 实现鸿蒙端设备的震动反馈
javascript·react native·react.js
WebGISer_白茶乌龙桃33 分钟前
Cesium实现“悬浮岛”式,三维立体的行政区划
javascript·vue.js·3d·web3·html5·webgl
不一样的少年_40 分钟前
产品催: 1 天优化 Vue 官网 SEO?我用这个插件半天搞定(不重构 Nuxt)
前端·javascript·vue.js
-dcr42 分钟前
50.智能体
前端·javascript·人工智能·ai·easyui