【问题标题】:HTTPInterceptor in angular 7 is behaving strangelyAngular 7 中的 HTTPInterceptor 行为异常
【发布时间】:2020-01-26 16:10:13
【问题描述】:

我有一个非常简单的拦截器,可以拦截错误并在控制台打印输出:

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(
        catchError((error: HttpErrorResponse) => {
            if (error.status == 401) {
                console.log("Error 401", error);
            }
            else if (error.status == 404) {
                console.log("Error 404", error);
            }
            else if (error.status == 0) {
                console.log("Unknown error", error);
                sendRequestAgain();
            } else{
               // do nothing
            }
            return throwError(error)
        })
    );
}

问题是当我得到error.status==0时,它第一次完美运行并再次发送请求(使用sendRequestAgain()),但是当第二次请求失败时,错误被正确拦截但控制不进入else if (error.status == 0) { 块。相反,它会下降到 else 块。我已经打印出错误,两次都完全相同。甚至else if (error.status == 0) { 上的断点也没有被第二次击中,这很奇怪。

有什么想法吗?

【问题讨论】:

  • catchError 操作符应该返回一个 Observable。尝试返回一些东西,看看你的错误是否仍然存在。
  • 感谢您的提示。让我试试看。
  • 更新了问题。我现在返回一个 observable
  • 还是一样的行为
  • console.log(error.status) 仍会显示 0?

标签: angular error-handling angular-http-interceptors


【解决方案1】:

您可以尝试合并 map 并检查错误是否是您要重试的错误,在这种情况下,我使用 404,如果是,则在处理下一个请求之前设置 rxjs 计时器,最后在使用操作员设置重试连接的时间。如果错误不是您要重试的错误,则只需再次追溯错误并像以前没有发生任何事情一样处理它。

import { Injectable } from '@angular/core';
import {
  HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse
} from '@angular/common/http';

import {Observable, throwError, timer} from 'rxjs';
import {catchError, mergeMap, retryWhen, take} from 'rxjs/operators';

@Injectable()
export class EnsureHttpsInterceptor implements HttpInterceptor {

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(
      retryWhen(errors => {
        return errors
          .pipe(
            mergeMap(error => error.status === 404 ? timer(5000) : throwError(error)),
            take(2)
          );
      }),
      catchError((error: HttpErrorResponse) => {

        switch (error.status) {
          case 401:
            console.log('Error 401', error);
            break;
          case 404:
            console.log('404', error);
            break;
          default:
            return throwError(error);
        }

      })
    );
  }
}

【讨论】:

  • 此代码仅重试两次。是否可以无限期重试?更重要的是,在后端启动之前继续重试是否是个好主意。我的服务在 docker swarm 中运行,如果服务崩溃,几乎可以保证服务迟早会启动。
  • @SaqibAhmed 在后端启动之前无限期地重试是不是一个好主意...除非您因延迟增加而退出。你可能会毁掉你苦苦挣扎的后端。
  • @AndrewAllen 好的。增加延迟似乎是一种更好的方法。那么如何修改上面的代码以无限期地尝试增加延迟呢?我可以想出一些东西来继续增加延迟,但 retryWhen 只重试两次。我该怎么办?
  • 尝试删除 take(2),但仍然重试两次:\
  • @SaqibAhmed exponential backoff 示例,但您也可以通过 http 拦截器对 api 调用的统计信息进行维护并采取适当的行动
猜你喜欢
  • 1970-01-01
  • 2019-06-21
  • 1970-01-01
  • 1970-01-01
  • 2019-09-19
  • 2019-07-16
  • 2021-11-16
  • 2012-08-02
  • 1970-01-01
相关资源
最近更新 更多