NestJS 拦截器实战:三个例子学会用

更新日期: 2026-04-16 阅读: 28 标签: Nest.js

一、拦截器是什么

拦截器就是一个类,它可以在请求处理前后加上你自己的代码。这个想法来自面向切面编程(AOP),说白了就是把一些通用的事情抽出来统一处理。

要写一个拦截器,需要用 @Injectable() 装饰器,还要实现 NestInterceptor 接口。里面必须写一个 intercept() 方法,这个方法有两个参数:

  • ExecutionContext:当前请求的上下文,里面有请求信息、控制器信息、方法信息等

  • CallHandler:调用处理器,通过它的 handle() 方法来执行真正的路由处理程序

有一点要记住:如果你在拦截器里不写 next.handle(),路由处理程序就不会执行。

下面是一个简单的日志拦截器例子:

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('请求进来了');
    const now = Date.now();
    return next.handle().pipe(
      tap(() => console.log(`请求处理完,花了 ${Date.now() - now} 毫秒`)),
    );
  }
}


二、拦截器能干什么

根据 NestJS 官方文档,拦截器可以做这些事:

  • 在方法执行前后加额外的逻辑

  • 改变函数返回的结果

  • 改变函数抛出的异常

  • 扩展函数的功能

  • 根据条件完全重写函数(比如做缓存)

看到这里你应该明白了,拦截器能做的事情确实不少。


三、三个常用例子

例子一:记录请求日志

这是拦截器最常用的场景。我们可以写一个日志拦截器,记下每个接口的请求参数、返回结果和花了多长时间。

上面的 LoggingInterceptor 就是一个基础版本。在实际项目中,你还可以把日志存到数据库里。

有个开发者分享过一个真实经历:产品经理要求记录每个用户的增删改查操作。他用拦截器轻松搞定了,记下了用户的操作类型、IP地址、请求参数、浏览器信息等。

小提示:要把日志存数据库,可以在拦截器里注入 Service。因为 handle() 返回的是 RxJS 的 Observable,用 switchMap() 或 tap() 就能在响应返回后去存数据库。

例子二:统一返回格式

如果你的接口需要统一的返回格式,拦截器可以帮你自动处理。

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

export interface Response<T> {
  statusCode: number;
  message: string;
  data: T;
}

@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
  intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
    return next.handle().pipe(
      map(data => ({
        statusCode: context.switchToHttp().getResponse().statusCode,
        message: '操作成功',
        data,
      })),
    );
  }
}

用了这个拦截器后,你每个接口的返回格式都会变成 { statusCode, message, data } 这种统一的样子。

例子三:处理超时

拦截器还可以配合 RxJS 的操作符来做请求超时控制和异常处理。

import { Injectable, NestInterceptor, ExecutionContext, CallHandler, RequestTimeoutException } from '@nestjs/common';
import { Observable, throwError, TimeoutError } from 'rxjs';
import { catchError, timeout } from 'rxjs/operators';

@Injectable()
export class TimeoutInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(
      timeout(5000),  // 5秒超时
      catchError(err => {
        if (err instanceof TimeoutError) {
          return throwError(() => new RequestTimeoutException('请求超时了'));
        }
        return throwError(() => err);
      }),
    );
  }
}


四、怎么用拦截器

1. 绑定到控制器或方法

用 @UseInterceptors() 装饰器可以指定拦截器在哪儿生效:

// 整个控制器都用
@Controller('cats')
@UseInterceptors(LoggingInterceptor)
export class CatsController {}

// 只在这个方法上用
@Get()
@UseInterceptors(LoggingInterceptor)
findAll() {
  return [];
}

2. 全局注册

想让拦截器对所有路由都生效,可以在模块里注册成全局的:

import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';

@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: LoggingInterceptor,
    },
  ],
})
export class AppModule {}

3. 注入依赖

拦截器和普通服务一样,可以通过构造函数注入其他服务,这样功能就更强大了。

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  constructor(private readonly loggerService: LoggerService) {}

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    this.loggerService.log('收到请求');
    return next.handle();
  }
}


五、拦截器和中间件有什么区别

很多初学者容易搞混这两个概念,我简单说一下:

特性中间件拦截器
执行时机只在请求到达控制器之前请求前后都可以
能不能改响应不能能(通过 RxJS)
能不能访问执行上下文不能
主要用途身份验证、CORS、日志响应转换、日志、缓存、异常处理

简单总结:中间件只能处理请求,拦截器既能处理请求也能处理响应。如果你需要改返回的数据格式,那就得用拦截器。

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/13630

相关推荐

在vue项目中使用canvas-nest.js,报parameter 1 is not of type Element

canvas-nest.js是一款轻量的网页特效。在vue项目中,使用时配置,引入canvas-nest.js后,直接在created中 new CanvasNest(element, config)。遇到parameter 1 is not of type Element这样类型的报错,需要检查dom是否渲染完毕。

从Express到Nestjs,谈谈Nestjs的设计思想和使用方法

最近已经使用过一段时间的nestjs,让人写着有一种java spring的感觉,nestjs可以使用express的所有中间件,此外完美的支持typescript,与数据库关系映射typeorm配合使用可以快速的编写一个接口网关。本文会介绍一下作为一款企业级的node框架的特点和优点。

初识Nest.js

最近在学习研究 Nest 框架,但是在学习过程中除了参考翻阅官方文档外国内几乎没有多少资料能系统的讲解 Nest 的相关内容,所以打算想通过我自己学习的角度讲解下 Nest 框架,不知道能坚持多久

Nest.js快速启动API项目

最近上了一个新项目,这个客户管理一个庞大的任务和团队集群,而不同流程所适用的系统也不太一样,比如salesforce,hubspots之类的。这次的新项目需要在另外两个平台之间做一些事情

聊聊 nestjs 中的依赖注入

在使用过程中会发现 nest 框架和后端同学使用的 Springboot 以及前端三大框架之一的 Angular 都有很多相似之处。没错这三个框架都有相似的设计,并都实现了依赖注入

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!