Search code examples
angularrxjs

How to set a custom request header using a HTTP Interceptor


I'm trying to add a custom request header for requests that go through the retry mechanism. I have an interceptor that currently filters any requests that specifically timeout while also logging the error details.

What I'm unsure of is, where do I set the header during the retry. I know the req.clone I currently have is incorrect but I having trouble figuring out how to access both the req and the error at the same time.

intercept(req: HttpRequest<any>, next: HttpHandler) {
return next.handle(req).pipe(
    timeout(30000),
    retryWhen((err) =>
        err.pipe(
            filter((error) => !(error instanceof ProgressEvent)),
            tap((error) => {
                // We'll keep track of the number of retries

                if (count > RETRY_COUNT) {
                    // abort retry
                } else {
                    // retry and set a custom header specifically to each of the retried requests

                    // This doesn't work since we are not changing the source observable and I don't think we even have access to the original req here.
                    const newReq = req.clone({
                        headers: req.headers.set('X-Retry-Count', count.toString())
                    })
                }
            }),
            delay(2000)
        )
    ),
    catchError((error) => {
        // Log the error...
    })
);}

Solution

  • You could achieve this using defer to create the original observable. defer allows you to define an observable factory that will get called with each subscription. This way you can create a different one for the first request and each of the retries.

    so you could do something like this:

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
      let retryCount = 0;
    
      // helper function to generate the request based on the current retryCount 
      function generateRequest() {
        return retryCount === 0
          ? req
          : req.clone({
              headers: req.headers.set('X-Retry-Count', retryCount.toString()),
            });
      }
    
    
      return defer(() => next.handle(generateRequest())).pipe(
        timeout(30000),
        retry({
          delay: (error) => {
            if (error instanceof ProgressEvent || retryCount >= MAX_RETRIES) {
              return throwError(() => error);
            }
    
            retryCount++;
            return timer(2000);
          },
        }),
        catchError((error) => {
          // Log the error...
        })
      );
    }