【问题标题】:Angular8 HttpInterceptor return valueAngular 8 Http拦截器返回值
【发布时间】:2020-03-14 02:47:32
【问题描述】:

我有一个基本的 HttpInterceptor,我在其中使用 rxjs retryWhen 以便在服务失败时重试一定次数。如果服务调用已达到最大重试次数,那么我想将此反馈给最初发起服务调用的方法。

我的问题是,我怎样才能将控制权交还给 http 调用的原始发起者? 我需要这样做以便在一个地方(拦截器)集中控制重试处理,并且我希望能够回调到调用函数中的成功/失败方法。

我的问题是错误被全局错误处理程序吞没了,没有任何东西传回给我的调用者。

例子:

this.MyServiceCall()
        .pipe(
          map((result) => {
            console.log('this is called when the service returns success');
          }),
         )
         // If there is an error, then how can I show it?
      })
    }


export class HttpRetryInterceptorService implements HttpInterceptor {
  constructor() { }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).pipe(
        retryWhen(errors => errors
            .pipe(
            concatMap((err:HttpErrorResponse, count) => iif(
            () => (count < 3),
            of(err).pipe(
                map(()=>{
                    console.log(count.toString())
                }),
                delay((2 + Math.random()) ** count * 200)),
                throwError(err)
            ))
        ))
    );
  }
}

【问题讨论】:

    标签: angular rxjs angular8 angular-http-interceptors retrywhen


    【解决方案1】:

    我认为您可以使用catchError 运算符。
    您仍然可以在一个地方(即:您的拦截器)处理错误,并通过 抛出错误 在您的 服务的 observable 中将错误委托给调用者将订阅。

    注意:如果您在拦截器中使用throwError 运算符,TS 应该会抱怨这个:

    intercept (req: HttpRequest<any>, next: HttpHandler) {
    //~~~~~~ 
        const foo = false;
    
        return next.handle(req)
        .pipe(
          map(ev => foo ? ev : throwError('err!')),
        )
    }
    

    错误是:

    类型 Observable 不能分配给类型 'HttpEvent'。

    HttpEvent 类型如下所示:

    export type HttpEvent<T> =
        HttpSentEvent | HttpHeaderResponse | HttpResponse<T>| HttpProgressEvent | HttpUserEvent<T>;
    

    所以,这里不允许出现错误。但这是我在this SO post 中找到的解决方法。

    intercept (req: HttpRequest<any>, next: HttpHandler) {
        const foo = false;
    
        return next.handle(req)
          .pipe(
            map(e => {
              if (e instanceof HttpResponse && !foo) {
                throw new HttpErrorResponse({
                  error: 'err'
                });
              }
    
              return e;
            })
        )
      }
    

    现在,delegated 错误应该在您的服务的 catchError 回调中捕获。

    this.MyServiceCall()
        .pipe(
            map((result) => {
                console.log('this is called when the service returns success');
            }),
            catchError(err => {
                // Do something with this error...
            })
        )
    

    编辑

    从拦截器中抛出错误也可以通过这种方式实现:

    intercept (req: HttpRequest<any>, next: HttpHandler) {
        const foo = false;
    
        return next.handle(req)
          .pipe(
          mergeMap(e => {
            if (!foo) {
              return throwError('err');
            }
    
            return of(e);
          }),
        )
      }
    

    我错过了 throwError 返回一个可观察的 :D 的事实。

    【讨论】:

    • 感谢您的详细回答 - 但是 retryWhen 呢 - 这就是复杂性
    【解决方案2】:

    尝试使用 catchError()

    this.MyServiceCall()
        .pipe(
            map((result) => {
                console.log('this is called when the service returns success');
            }),
            catchError((error) => {
                // Do something and return either an observable or rethrow the error
                return throwError(error);
            })
        );
    

    https://www.learnrxjs.io/operators/error_handling/catch.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 2017-11-07
      • 2018-05-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多