Angular - HTTP interceptor to retry requests with specific error status?

前端 未结 2 1254
生来不讨喜
生来不讨喜 2021-01-01 06:33

I am trying to use an interceptor to handle http errors and retry for a special error status, in my case the status code 502.

intercept(request: HttpRequest&         


        
相关标签:
2条回答
  • 2021-01-01 07:16

    Try the below code. You should do it the other way round.

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(request)
          .pipe(
            retryWhen(errors => {
              return errors
                .pipe(
                  mergeMap(error=>error.status === 502?timer(0):throwError(error)),
                  take(2)
                )
            }),
            catchError((error: HttpErrorResponse) => {
              return throwError(error);
            })
          )
      }
    
    0 讨论(0)
  • 2021-01-01 07:27

    I took your approach and expanded it a little, out of own interest.

    The first would be to create a sort of custom operator:

    import { timer, throwError, Observable } from 'rxjs';
    import { mergeMap } from 'rxjs/operators';
    
    export interface RetryParams {
      maxAttempts?: number;
      scalingDuration?: number;
      shouldRetry?: ({ status: number }) => boolean;
    }
    
    const defaultParams: RetryParams = {
      maxAttempts: 3,
      scalingDuration: 1000,
      shouldRetry: ({ status }) => status >= 400
    }
    
    export const genericRetryStrategy = (params: RetryParams = {}) => (attempts: Observable<any>) => attempts.pipe(
      mergeMap((error, i) => {
        const { maxAttempts, scalingDuration, shouldRetry } = { ...defaultParams, ...params }
        const retryAttempt = i + 1;
        // if maximum number of retries have been met
        // or response is a status code we don't wish to retry, throw error
        if (retryAttempt > maxAttempts || !shouldRetry(error)) {
          return throwError(error);
        }
        console.log(`Attempt ${retryAttempt}: retrying in ${retryAttempt * scalingDuration}ms`);
        // retry after 1s, 2s, etc...
        return timer(retryAttempt * scalingDuration);
      })
    );
    

    You can then construct an interceptor based on this operator as follows:

    @Injectable()
    export class RetryInterceptor implements HttpInterceptor {
      intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        const { shouldRetry } = this;
        return next.handle(request)
          .pipe(retryWhen(genericRetryStrategy({
            shouldRetry
          })));
      }
    
      private shouldRetry = (error) => error.status === 502;
    }
    

    You can see it working in this blitz

    0 讨论(0)
提交回复
热议问题