在角度6中重试HTTP请求

Ami*_*emi 6 javascript http rxjs angular

我使用拦截器根据每个请求的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);
            })
        );
}
Run Code Online (Sandbox Code Playgroud)

在我的项目中,Web服务器有时可能无法使用一秒钟,然后回复500错误代码。我不希望我的网络应用在收到错误后立即显示错误消息,并且希望它重试请求几次,但要延迟一秒钟。

我已经尝试过rxjs retry:

...
.handle(customReq).pipe(retry(5),
...
Run Code Online (Sandbox Code Playgroud)

这没有用,因为它没有延迟。基于此答案 如何创建具有延迟和尝试限制的RXjs RetryWhen

我尝试了retryWhen

.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));
    }),
Run Code Online (Sandbox Code Playgroud)

但它不能按预期运行,并且不会进入if条件内。

m1c*_*4ls 10

您的代码中有几个错误:

  1. 您正在隐藏error变量-首先是错误流,然后是错误对象。
  2. 使用observableThrowErrorwith delay无效。错误将绕过除处理错误的运算符之外的所有运算符。
  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)
        )
    ),
Run Code Online (Sandbox Code Playgroud)

主要变化是通过第二个参数concatMap而不是使用takeopeator 来跟踪错误计数,这主要用于取消订阅可观察对象,我想您想抛出一个错误。