nest 拦截器

时间:2023-01-09 浏览:176 分类:NestJS

拦截器具有一组有用的功能,这些功能的灵感来自面向方面的编程 (AOP) 技术。拦截器的作用是:

  • 1. 在方法执行之前/之后绑定额外的逻辑

  • 2. 转换函数返回的结果

  • 3. 转换函数抛出的异常

  • 4. 扩展基本功能行为

  • 5. 根据特定条件完全覆盖函数(例如,出于缓存目的)

使用:

第一步:创建拦截器

logging.interceptor.ts

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> {
    const request = context.switchToHttp().getRequest();
    const response = context.switchToHttp().getResponse();
    console.log('Before...');

    return next.handle();
  }
}

其中 next.handle() 方法之前是请求拦截之前的处理逻辑,常用的是处理request 请求;next.handle() 方法之后是处理拦截之后的逻辑,常常用来修改response 的返回逻辑,这里使用到Rxjs 库。

Rxjs是一种响应式编程(RP)的实现框架。其中Observable字面意识是可观察,所谓的观察就是当事件发生时,由事件发生之前的所指派的函数来处理数据输入。这个指派的过程就是订阅,而事件的发生过程是一个发布。即提前定义好相应发生后的逻辑,待数据发生后使用之前定义好的逻辑处理,这个流中会三种类型的值,分别是正常产生的值,被触发的异常和整个流结束信号。

创建数据流的方法有:

fromEvent() 和 of()

管道操作方法:

// Observable.pipe(op1,op2,op3...)

map:可以修改输入的值,再输出。类似于JS的map函数;
tap:每次输入值后接收,但不改变值;
timeout:设置一个过期时间,当这个时间段内没有接收到完成信号就会出发这个逻辑;
catchError:当管道中发生异常(throw)后,执行的操作;

第二步:nest绑定引入拦截器

// user.controller.ts

@UseInterceptors(LoggingInterceptor)
export class UserController {}

全局引入:

// main.ts 

// 方法一:
const app = await NestFactory.create(AppModule);
app.useGlobalInterceptors(new LoggingInterceptor());
// app.module.ts

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

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

请求后response 的反馈逻辑处理

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

@Injectable()
export class UserInterceptor implements NestInterceptor {
    intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        const request = context.switchToHttp().getRequest();
        const response = context.switchToHttp().getResponse();

        console.log('Before...');  
        return next.handle().pipe(         // next.handle() 返回Observable对象
            tap((data) => console.log('After...', data)),  // tap作用接收response 返回值,不做任何处理
            map(() => {            // map为接受response 返回值,并处理后输出
                return {res: 2};   
            }),
            timeout(1000),     // 超时定义
            catchError(err => {    // 异常捕获,可以输出
                return of({res: 3});
            })
        );
    }
}

客户端在正常http 请求之后,终端可以看到先后执行顺序为:

Middleware   ===> 中间件先执行
guard here /user   ===> 随后守卫
Before...   ===> 拦截器相应前的处理(多是request)
index query Person { name: 'ljd', age: 12 }   ===> 正常相应结果
After... { res: 2 }     ===> response 后的逻辑处理,这里看到上面After 输出并在浏览器看到了修改后的res: 2结果