最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Retry HTTP requests in angular 6 - Stack Overflow

programmeradmin1浏览0评论

I use an interceptor to show error messages on display based on the HTTP response for every request.

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);
            })
        );
}

In my project, the web server could be unavailable for a second in some case and reply a 500 error code. I don't want my web app to show an error message immediately after receiving an error and I want it to retry the request for a couple of times with a delay like one second.

I already tried rxjs retry :

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

it's not useful since it has no delay. based on this answer How to create an RXjs RetryWhen with delay and limit on tries

I tried 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));
    }),

but it doesn't work as expected and it doens't go inside the if conditions.

I use an interceptor to show error messages on display based on the HTTP response for every request.

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);
            })
        );
}

In my project, the web server could be unavailable for a second in some case and reply a 500 error code. I don't want my web app to show an error message immediately after receiving an error and I want it to retry the request for a couple of times with a delay like one second.

I already tried rxjs retry :

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

it's not useful since it has no delay. based on this answer How to create an RXjs RetryWhen with delay and limit on tries

I tried 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));
    }),

but it doesn't work as expected and it doens't go inside the if conditions.

Share Improve this question edited Aug 18, 2018 at 16:57 m1ch4ls 3,43520 silver badges31 bronze badges asked Aug 18, 2018 at 6:35 Amir KhademiAmir Khademi 2731 gold badge6 silver badges13 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 14

There are several errors in your code:

  1. You are shadowing error variable - first it's an error stream and then it's an error object.
  2. Using observableThrowError with delay has no effect. Error will bypass every operator except those dealing with error.
  3. You are mixing "pipe(operator())" style operators and prototype style operators .operator().

I have suggested some changes:

.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)
        )
    ),

Main change is tracking error count through second argument of concatMap instead of using take opeator which is mainly useful for unsubscribing the observable and I think you want throw an error instead.

You could use retry operator, better to use it on an interceptor

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

It will only retry when the request fails, then to identify errors you could throw an error and then catch it

.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;
}));

Don't forget t return EMPTY because the interceptor needs to return an observable

发布评论

评论列表(0)

  1. 暂无评论