【问题标题】:Retry HTTP requests in angular 6以角度 6 重试 HTTP 请求
【发布时间】:2018-08-18 06:35:10
【问题描述】:

我使用拦截器根据每个请求的 HTTP 响应显示错误消息。

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const customReq = request.clone({
        //headers: request.headers.set('app-language', 'en')
    });
    return next
        .handle(customReq).pipe(
            tap((ev: HttpEvent<any>) => {
                if (ev instanceof HttpResponse) {
                    // processing request
                }
            }),
            catchError(response => {
                if (response instanceof HttpErrorResponse) {
                    switch (response.status) {
                        case 0:
                            // server API connection error show
                            break;
                        case 403:
                            // error Token Invalid and Redirect to logout
                            break;
                        case 401:
                            // error Token Invalid and Redirect to logout
                            break;
                        case 502:
                            // Bad gateway error
                            break;
                        case 500:
                            // internal server error
                            break;
                    }
                }
                // return next.handle(request);
                return observableThrowError(response);
            })
        );
}

在我的项目中,Web 服务器在某些情况下可能会出现一秒钟不可用并回复 500 错误代码。我不希望我的网络应用在收到错误后立即显示错误消息,我希望它在延迟一秒的情况下重试请求几次。

我已经尝试过 rxjs 重试:

...
.handle(customReq).pipe(retry(5),
...

它没有用,因为它没有延迟。 基于这个答案 How to create an RXjs RetryWhen with delay and limit on tries

我试过 retryWhen like:

.handle(customReq).pipe(
    tap((ev: HttpEvent<any>) => {
        if (ev instanceof HttpResponse) {
            console.log('###processing response', ev, this.location);
        }
    }),
    retryWhen(error => {
        return error
            .flatMap((error: any) => {
                if (error.status  == 400) {
                    return Observable.of(error.status).delay(1000);
                }
                if (error.status  == 0) {
                    return observableThrowError(error).delay(1000);
                }
                return observableThrowError(error);
            })
            .take(5)
            .concat(observableThrowError(error));
    }),

但它没有按预期工作,并且没有进入 if 条件。

【问题讨论】:

    标签: javascript angular http rxjs


    【解决方案1】:

    您的代码中有几个错误:

    1. 您正在隐藏 error 变量 - 首先它是一个错误流,然后是一个错误对象。
    2. observableThrowErrordelay 一起使用没有效果。 Error 将绕过所有运算符,除了那些处理错误的运算符。
    3. 您正在混合使用“pipe(operator())”样式运算符和原型样式运算符.operator()

    我提出了一些更改建议:

    .handle(customReq).pipe(
        tap((ev: HttpEvent<any>) => {
            if (ev instanceof HttpResponse) {
                console.log('###processing response', ev, this.location);
            }
        }),
        retryWhen(errors => errors
            .pipe(
                concatMap((error, count) => {
                    if (count < 5 && (error.status == 400 || error.status == 0)) {
                        return Observable.of(error.status);
                    }
    
                    return observableThrowError(error);
                }),
                delay(1000)
            )
        ),
    

    主要变化是通过 concatMap 的第二个参数而不是使用 take 操作符来跟踪错误计数,这主要用于取消订阅 observable,我认为您想抛出一个错误。

    【讨论】:

    • 我会说阿米尔的代码有更多的问题。他将用户重定向到拦截器内的登录页面(至少根据 cmets 拦截器是这样做的),这应该是 guard 的工作。
    【解决方案2】:

    你可以使用重试操作符,最好在拦截器上使用它

     intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(request)
            .pipe(retry(RETRY_NUMBER))
    

    它只会在请求失败时重试,然后为了识别错误,你可以抛出一个错误然后捕获它

    .pipe(tap(event => {
                // tipo http
                if (event instanceof HttpResponse) {
                    if (event.body && event.body.error === true && event.body.errorMessage) {
                        throw new Error(event.body.errorMessage);
                    }
                }
            }))
    
    
    .pipe(catchError((err) => {
    
          if (err.status === 0) {
              //do something
          }
          // other conditions ...
    
          return EMPTY;
    }));
    

    不要忘记返回 EMPTY 因为拦截器需要返回一个 observable

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-09
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      • 1970-01-01
      相关资源
      最近更新 更多