NestJS:拦截器映射和catchError

Jas*_*ues 3 node.js express rxjs typescript nestjs

我需要一个 NestJS 拦截器来归档请求,无论是在例外情况还是在正常情况下。创建如下:

public intercept(context: ExecutionContext, next: CallHandler): Observable<any> {

    if (!this.reflector.get<boolean>(RequestMetaData.IS_PUBLIC_ROUTE, context.getHandler())) {
        return next.handle().pipe(
          map(data => {
              const host = context.switchToHttp();
              const req = host.getRequest();
              const resp = host.getResponse();
              this.persistRequest(data, req, resp)
                .then(() => this.logger.log(`Request logged`))
                .catch(e => {
                    this.logger.error(`Error logging request: ${e.message}`);
                });
              return data;
          }));
    }
    return next.handle();
}
Run Code Online (Sandbox Code Playgroud)

问题:

这只会记录快乐路径。因为我不熟悉 RxJS,所以我创建了另一个来持久化错误。例如:

public intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next
      .handle()
      .pipe(
        catchError(err => {
            return throwError(err);
        })
      );
}
Run Code Online (Sandbox Code Playgroud)

如何定义一个拦截器来归档两条路径?

Mic*_*ons 5

我认为您在这里使用了错误的运算符。内部映射也返回一个发布者。

您应该使用 转换外部发布者,flatMap以便创建一个流,而不是嵌套流。

这是纯 RxJS 6 中的示例:

import { of, EMPTY } from 'rxjs';
import { map, flatMap, catchError } from 'rxjs/operators';

of(3,2,1,0,1,2,3).pipe(
  flatMap(v => {
    return of(v).pipe(
      map(x => {    
        if(x===0) throw Error();
        return 6 / x;
      }), 
      catchError(error => {
        console.log("Shit happens")
        return EMPTY
      }
    )
    )
  } 
))
.subscribe(val => console.log("Request " + val + " logged "));
Run Code Online (Sandbox Code Playgroud)

每个请求(这里是数字)都是一个平面映射到一个持久化的东西。平面映射意味着,持久化器再次返回一个可观察对象。见https://rxjs-dev.firebaseapp.com/api/operators/flatMap

这些内部 observable 的错误处理是通过catchError操作符完成的。它记录错误,然后返回一个空的 observable 以指示内部 observable 是“死的”。你可以在这里返回另一个 observable,然后内部会继续。

外部 observable,即您传入的请求,会在此过程中继续每个。

我在这里创建了一个 stackblitz 应用程序:

https://rxjs-qkqkm2.stackblitz.io

祝 NestJS 和所有不同版本的 RxJS 好运。以上是第 6 版。

编辑:

RxJStap方法是处理副作用的好方法。实现拦截方法如下:

public intercept(context: ExecutionContext, next: CallHandler): Observable<any> {

    if (!this.reflector.get<boolean>(RequestMetaData.IS_PUBLIC_ROUTE, context.getHandler())) {

        const host = context.switchToHttp();
        const req = host.getRequest();
        const resp = host.getResponse();

        return next.handle().pipe(
          tap({
              next: (val) => {
                  this.persistRequest(val, req, resp);
              },
              error: (error) => {
                  this.persistRequest(AppError.from(error), req, resp);
              }
          })
        );
    }
    return next.handle();
}
Run Code Online (Sandbox Code Playgroud)