美文网首页
Nest.js - 拦截器

Nest.js - 拦截器

作者: stevekeol | 来源:发表于2020-07-13 17:29 被阅读0次
    概念

    拦截器使用@Injectable装饰器,并实现NestInterceptor接口。

    • 在函数执行之前/之后绑定额外的逻辑
    • 转换从函数返回的结果
    • 转换从函数抛出的异常
    • 扩展基本函数行为
    • 根据所选条件完全重写函数(如缓存目的)
    自定义拦截器
    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 now = Date.now();
        return next
          .handle()
          .pipe(
            tap(() => console.log(`After... ${Date.now() - now}ms`));
          );
      }
    }
    
    • 每个拦截器都有intercept(ExecutionContext, CallHandler)方法,第一个参数是执行上下文,第二个参数是调用处理程序
    • CallHandler是一个包装执行流的对象。因此。必须手动调用hander()方法,最终方法才会被触发;
    • 在函数执行前后添加额外的逻辑。在需要记录与应用程序的交互时很有用。如存储用户调用异步调度事件计算时间戳
      +handle()返回一个Observable,可使用tap()等运算符,在可观察序列的正常/异常终止时调用函数
    绑定拦截器
    //@UseInterceptors(new LoggingInterceptor())
    @UseInterceptors(LoggingInterceptor)
    export class CatsController {}
    
    • 拦截器的范围有: 方法层面,控制器层面,全局层面
    响应映射

    handle()返回一个Observable,该流包含了从路由处理程序返回的值,可使用map()运算符改变它。

    import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
    import { Observable } from 'rxjs';
    import { map } from 'rxjs/operators';
    
    export interface Response<T> {
      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 => ({ data })));
      }
    }
    
    • 创建的TransformInterceptor将打包响应并将其分配给data属性
    • 假如处理程序返回空数组[],请求将被改写成:{ data: [] }

    例如需要在全局将每个发生的null值转换成空字符串'',可使用一行代码将拦截器绑定为全局代码。

    // 定义拦截器
    import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
    import { Observable } from 'rxjs';
    import { map } from 'rxjs/operators';
    
    @Injectable()
    export class ExcludeNullInterceptor implements NestInterceptor {
      intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        return next
          .handle()
          .pipe(map(value => value === null ? '' : value ));
      }
    }
    
    // 绑定拦截器
    const app = await NestFactory.create(ApplicationModule);
    app.useGlobalInterceptors(new ExcludeNullInterceptor ());
    
    异常映射

    利用catchError()操作符来覆盖抛出的异常

    // exception.interceptor.ts
    import {
      Injectable,
      NestInterceptor,
      ExecutionContext,
      BadGatewayException,
      CallHandler,
    } from '@nestjs/common';
    import { Observable, throwError } from 'rxjs';
    import { catchError } from 'rxjs/operators';
    
    @Injectable()
    export class ErrorsInterceptor implements NestInterceptor {
      intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        return next
          .handle()
          .pipe(
            catchError(err => throwError(new BadGatewayException())),
          );
      }
    }
    
    Stream重写

    假如由于性能问题,需要从缓存中获取。如缓存拦截器,希望完全阻止调用处理程序,并返回不同的值。

    // cache.interceptor.ts
    import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
    import { Observable, of } from 'rxjs';
    
    @Injectable()
    export class CacheInterceptor implements NestInterceptor {
      intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        const isCached = true;
        if (isCached) {
          return of([]);
        }
        return next.handle();
      }
    }
    
    • 此处有硬编码的isCached变量和响应[],通过of()运算符创建并返回一个新的流,因此路由处理程序根本不会被调用;
    • 为了更好地通用性,可以利用Reflector反射器创建自定义修饰符。
    更多操作符

    Rxjs运算符操作流提供了很多功能。

    // timeout.interceptor.ts
    
    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),
          catchError(err => {
            if (err instanceof TimeoutError) {
              return throwError(new RequestTimeoutException());
            }
            return throwError(err);
          }),
        );
      };
    };
    
    
    • 5秒后,请求处理将被取消。您还可以在抛出之前添加自定义逻辑RequestTimeoutException(例如,释放资源)。

    相关文章

      网友评论

          本文标题:Nest.js - 拦截器

          本文链接:https://www.haomeiwen.com/subject/dyxzcktx.html