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

相关推荐
Joker`s smile17 分钟前
使用React+ant Table 实现 表格无限循环滚动播放
前端·javascript·react.js
然我23 分钟前
从原生 JS 到 React:手把手带你开启 React 业务开发之旅
javascript·react.js·前端框架
wkj00131 分钟前
QuaggaJS 配置参数详解
java·linux·服务器·javascript·quaggajs
阿琳a_42 分钟前
前端对WebSocket进行封装,并建立心跳监测
前端·javascript·vue.js·websocket
Am1nnn1 小时前
【Pinia】Pinia和Vuex对比
前端·javascript·vue.js
可爱小仙子1 小时前
ios苹果系统,js 滑动屏幕、锚定无效
前端·javascript·ios
大得3691 小时前
react菜单,动态绑定点击事件,菜单分离出去单独的js文件,Ant框架
前端·javascript·react.js
古夕1 小时前
Promise A+ 规范解读
前端·javascript
古夕1 小时前
Promise 基础概念与实践详解
前端·javascript
我想说一句1 小时前
React组件化开发实战:从"待办事项"看前端乐高搭建术
前端·javascript·react.js