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.
In other words, we can say that the RxJS retry() operator is used to handle and take care of retrying back on the source observable if it finds there any error and then retry according to the input count given.
ReTry & ReTryWhen Operators help us to retry a failed observable in Angular. These operators are useful in Error handling. They both resubscribe to the source observable when they receive onError() notification.
There are several errors in your code:
error
variable - first it's an error stream and then it's an error object.observableThrowError
with delay
has no effect. Error will bypass every operator except those dealing with error.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With