Skip to content

拦截器

拦截器和中间件的不同处

  • 中间件的执行时机要早于拦截器

中间件的执行时机要早于拦截器

  • 中间件是可以中断不合法的请求的,拦截器不行

拦截器是对控制器方法的增强或者削弱,它必须依赖于控制器的方法

  • 中间件无法知道处理当前请求的控制器和处理请求的控制器方法

拦截器可以知道.拦截器能够利用反射获取到控制器或方法上的一些元数据,从而判断token,鉴权之类的

拦截器种类和位置

种类

  1. 全局拦截器

  2. 控制器拦截器

  3. 路由拦截器

位置

  1. 前置拦截器

  2. 后置拦截器

拦截器使用

按照位置(来说)

  • 先创建一个拦截器起名 : xxxx.interceptor.ts
ts
import {
  CallHandler,
  ExecutionContext,
  Injectable,
  NestInterceptor,
  Inject,
  HttpException,
} from "@nestjs/common";
import { Observable, map, of } from "rxjs";
import { Request } from "express";
import { WINSTON_MODULE_PROVIDER } from "nest-winston";
import { Logger } from "winston";
import { getReqMainInfo } from "../utils/utils";

@Injectable()
export class GlobalInterceptor implements NestInterceptor {
  constructor(
    @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger
  ) {}

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    /* 前置拦截器 */
    /* 判断有没有token,没有就不要进入路由 直接返回,有则放行 */
    /* 这里返回用of,你抛出异常也可以会记录到日志,所以一般用of */
    const ctx = context.switchToHttp();
    const req = ctx.getRequest<Request>();
    // 获取路径
    const url = req.url;
    const token = req.headers["access-token"];
    if (token) {
      return of({
        code: 401,
        msg: "token不存在",
      });

      // 或者直接抛出异常
      // throw new HttpException('token不存在', 401);
    }
    /* 前置拦截器结束 */
    /* 后置拦截器 */
    /* 统一回复管理 */
    return next.handle().pipe(
      map((data) => {
        // 记录请求日志
        this.logger.info("response", {
          responseData: data,
          req: getReqMainInfo(req),
        });
        // 设置响应头
        ctx.getResponse().set("access-token", token);
        // 设置相应头部
        ctx.getResponse().set("test", "hehhe");
        // 返回数据
        return {
          code: 200,
          data,
          msg: "success",
        };
      })
    );
  }
}

拦截器功能

  • 全局拦截器

找到 app.module.ts 文件,在 providers 中添加

ts
// 拦截器
// 引入类型 方便挂载全局
import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core';
// 引入 你自己的拦截器
import { GlobalInterceptor } from './global/interceptor/global.interceptor';
@Module({
  imports: [],
  controllers: [],
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: GlobalInterceptor,
    },
  ],
})

这样全局都可以使用

  • 控制器使用

在你自己的控制器 xxxxx.controller.ts 中添加

这样这个路由下面的所有路由都会使用这个拦截器

ts
// 引用
import { UseInterceptors } from "@nestjs/common";
import { GlobalInterceptor } from "src/global/interceptor/global.interceptor";

@Controller("logins")
@UseInterceptors(GlobalInterceptor)
export class LoginController {
  // .......
}
  • 针对单个方法
ts
// 引用
import { UseInterceptors } from "@nestjs/common";
import { GlobalInterceptor } from "src/global/interceptor/global.interceptor";

@Controller("logins")
export class LoginController {
  @Get("test")
  @UseInterceptors(GlobalInterceptor)
  test() {
    return "test";
  }
}