视频教程
23_nestjs中的拦截器_哔哩哔哩_bilibili
1. rxjs 介绍
RxJS(Reactive Extensions for JavaScript)是一款专为JavaScript和TypeScript设计的响应式编程库,它遵循ReactiveX规范,提供了一套强大的工具和API,用于处理异步数据流和事件驱动编程。RxJS引入了可观察对象(Observable)的概念,这是一种可以推送多个值、错误或完成通知的数据源。
RxJS的核心特性包括:
- Observable:可观察对象是RxJS中最基本的数据类型,它代表了未来可能发出0个或多个值的异步数据流。开发者可以通过订阅(subscribe)Observable来消费它的值,订阅过程中可以指定处理值(next handler)、错误(error handler)和完成(complete handler)的回调函数。
- 操作符(Operators):RxJS有一系列丰富的操作符,可以用来变换、组合、过滤、聚合Observable发出的值。例如,map用于将值映射到另一个值,filter用于筛选满足条件的值,merge用于合并多个Observable的输出,switchMap用于基于当前值切换到另一个Observable等。
- 组合能力:RxJS能够将多个异步操作无缝地串联起来,形成复杂的异步流水线,使得代码更加清晰和易于理解。通过操作符可以处理多个异步事件流的并发和依赖关系。
- 响应式编程:RxJS有助于实现响应式编程模式,这种模式下,数据流被视为时间和空间上的变化,并可以实时地反应这些变化。无论是用户界面事件、网络请求、计时器事件还是其他任何产生异步数据的源头,都能抽象成Observable,进而采用统一的方式进行处理。
- 错误处理和背压支持:RxJS提供了良好的错误处理机制,当Observable遇到错误时,可以通过错误处理器进行恰当的应对。另外,对于高频率数据流,RxJS也支持背压(Backpressure),防止消费者来不及处理生产者产生的大量数据而导致内存溢出等问题。
中文网站地址:RxJS 中文版
有兴趣的话,大家可以自己去看看。我们这主要讲nest拦截器中用到的rxjs
2. 创建项目
nest new interceptor -p pnpm
3. 响应拦截器
nest g interceptor response --flat --no-spec
生成的代码
我们修改一下
import { Injectable, NestInterceptor, CallHandler, ExecutionContext } from '@nestjs/common'
import { map } from 'rxjs/operators'
import type { Observable } from 'rxjs';interface data<T> {data: T
}@Injectable()
export class ResponseIntercept<T = any> implements NestInterceptor {intercept(context: ExecutionContext, next: CallHandler): Observable<data<T>> {return next.handle().pipe(map(data => {return {data,code: 200,message: "success"}}))}
}
注:map:对响应数据做修改,一般都是改成 {code, data, message} 的格式
我们可以路由级别启用
还可以全局启用,记得注释掉刚刚路由启用的拦截器
路由级别和全局级别的 拦截器 的区别,路由级别的可以注入依赖,而全局的不行,全局 拦截器 可以通过 APP_INTERCEPTOR 的 token 声明,这种能注入依赖,比 app.useGlobalInterceptors 更好。(前面aop时有讲到)
4. 超时拦截器
接口如果长时间没返回,就给用户一个接口超时的响应
nest g interceptor timeout --flat --no-spec
import { CallHandler, ExecutionContext, Injectable, NestInterceptor, RequestTimeoutException } from '@nestjs/common';
import { catchError, Observable, throwError, timeout, TimeoutError } from 'rxjs';@Injectable()
export class TimeoutInterceptor implements NestInterceptor {intercept(context: ExecutionContext, next: CallHandler): Observable<any> {return next.handle().pipe(timeout(3000),catchError(err => {if (err instanceof TimeoutError) {console.log('Timeout error!');return throwError(() => new RequestTimeoutException());}return throwError(() => err);}))}
}
timeout 操作符会在 3s 没收到消息的时候抛一个 TimeoutError。然后用 catchError 操作符处理下,如果是 TimeoutError,就返回 RequestTimeoutException,这个有内置的 exception filter 会处理成对应的响应格式。
大家注意,如果有的浏览器可能会触发多次
- timeout:处理响应超时的情况,抛出一个 TimeoutError,配合 catchErrror 可以返回超时的响应
- catchError:在 exception filter 之前处理抛出的异常,可以记录或者抛出别的异常