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

相关推荐
冴羽10 分钟前
SvelteKit 最新中文文档教程(3)—— 数据加载
前端·javascript·svelte
云隙阳光i40 分钟前
实现手机手势签字功能
前端·javascript·vue.js
柠檬树^-^2 小时前
app.config.globalProperties
前端·javascript·vue.js
起来改bug2 小时前
【pptx-preview】react+pptx预览
javascript·react.js·pptx
马可奥勒留3 小时前
声明
javascript
团酱4 小时前
控制台报错:The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0.
开发语言·javascript·sass
清羽_ls4 小时前
react useEffect函数清除副作用函数执行时机
前端·javascript·react.js
難釋懷5 小时前
JavaScript数据类型简介
前端·javascript
Riesenzahn5 小时前
TypeScript中支持的访问修饰符有哪些?
前端·javascript
打野赵怀真5 小时前
如何使用html5进行图片压缩上传?
前端·javascript