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

相关推荐
大橙子额2 小时前
【解决报错】Cannot assign to read only property ‘exports‘ of object ‘#<Object>‘
前端·javascript·vue.js
WooaiJava3 小时前
AI 智能助手项目面试技术要点总结(前端部分)
javascript·大模型·html5
Never_Satisfied3 小时前
在JavaScript / HTML中,关于querySelectorAll方法
开发语言·javascript·html
董世昌413 小时前
深度解析ES6 Set与Map:相同点、核心差异及实战选型
前端·javascript·es6
WeiXiao_Hyy4 小时前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
xjt_09015 小时前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农5 小时前
Vue 2.3
前端·javascript·vue.js
辰风沐阳5 小时前
JavaScript 的宏任务和微任务
javascript
冰暮流星6 小时前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_6 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js