Вы можете использовать оператор retryWhen
. Принцип, лежащий в основе этого, заключается в том, что вы выдаете ошибку, когда не хотите повторить попытку.
retryWhen
фактически является фантастическим catchError
, который автоматически повторяет попытку, если не будет выдана ошибка .
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
// retryWhen operator should come before catchError operator as it is more specific
retryWhen(errors => errors.pipe(
// inside the retryWhen, use a tap operator to throw an error
// if you don't want to retry
tap(error => {
if (error.status !== 500 && error.status !== 502) {
throw error;
}
})
)),
// now catch all other errors
catchError(error => {
if (error.status === 401 || error.status === 400 || error.status === 403) {
this.router.navigateByUrl('abort-access', { replaceUrl: true });
}
return throwError("error occured");
})
);
}
DEMO: https://stackblitz.com/edit/angular-qyxpds
Ограничение повторных попыток
Опасность заключается в том, что вы будете выполнять непрерывные запросы, пока сервер не выполнит не верните 500 или 502. В реальном приложении вы хотели бы ограничить количество повторных попыток и, возможно, добавить некоторую задержку, чтобы избежать переполнения вашего сервера запросами.
Чтобы сделать это, вы могли бы используйте take(n)
, что ограничит ваши запросы n
неудачными попытками. Это не будет работать для вас, потому что take
остановит наблюдаемое от перехода к catchError
, и вы не сможете выполнять навигацию.
Вместо этого вы можете установить предел повторных попыток и бросить ошибка после достижения предела повторных попыток.
const retryLimit = 3;
let attempt = 0;
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
// retryWhen operator should come before catchError operator as it is more specific
retryWhen(errors => errors.pipe(
tap(error => {
if (++attempt >= retryLimit || (error.status !== 500 && error.status !== 502)) {
throw error;
}
})
)),
// now catch all other errors
catchError(error => {
if (error.status === 401 || error.status === 400 || error.status === 403) {
this.router.navigateByUrl('abort-access', { replaceUrl: true });
} else if (error.status === 500 || error.status === 502) {
this.router.navigateByUrl('server-error', { replaceUrl: true });
// do not return the error
return empty();
}
return throwError("error occured");
})
);
}
DEMO: https://stackblitz.com/edit/angular-ud1t7c