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

相关推荐
xiaoxue..11 分钟前
哨兵节点与快慢指针解决链表算法难题
前端·javascript·数据结构·算法·链表
尽欢i17 分钟前
踩过坑才懂:前端生成唯一 ID,别用 Date.now ()了!一行代码搞定
前端·javascript
JS_GGbond17 分钟前
解锁 JavaScript 对象的“魔法宝箱”:这些方法让你玩转对象操作
前端·javascript
Doris89319 分钟前
【JS】JS进阶--编程思想、面向对象构造函数、原型、深浅拷贝、异常处理、this处理、防抖节流
开发语言·javascript·ecmascript
福大大架构师每日一题23 分钟前
rust 1.92.0 更新详解:语言特性增强、编译器优化与全新稳定API
java·javascript·rust
Можно29 分钟前
ES6扩展运算符:从基础到实战的全方位解析
前端·javascript
豆苗学前端30 分钟前
闭包、现代JS架构的基石(吊打面试官)
前端·javascript·面试
雯0609~33 分钟前
uni-app:防止重复提交
前端·javascript·uni-app
爱吃大芒果33 分钟前
Flutter 自定义 Widget 开发:从基础绘制到复杂交互
开发语言·javascript·flutter·华为·ecmascript·交互
2501_9181269137 分钟前
用html5写一个国际象棋
前端·javascript·css