Search code examples
angularangular-http-interceptors

Not able to retry the same request after refresh call in Anuglar


I am not able to retry the same request after the refresh call. I have tried next.handle(updated_request) but still, it is not running. Can you please help with this.

FYI: I have attached my code here. Please let me know, If I missed anything here.

intercept (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  this.presentLoading();
  const headerSettings = req.headers.keys().reduce((acc, cur) => {
    acc[cur] = req.headers.getAll(cur);
    return acc;
  }, {});
  return fromPromise(this.storage.get('userdata')).pipe(mergeMap((token: any) => {
    if(token)
      headerSettings["Authorization"] = token.access_token;
    let headers = new HttpHeaders(headerSettings),
    newRequest = req.clone({ headers });
    return next.handle(newRequest)
      .pipe(catchError((err: any) => {
          if (err instanceof HttpErrorResponse) {
              // token is expired refresh and try again
              if (err.status === 401) {
                if(token && token.refresh_token) {
                  this.login.refresh(token.refresh_token).subscribe((data: any) => {
                    if(data.data)
                      headerSettings["Authorization"] = data.data.access_token;
                    headers = new HttpHeaders(headerSettings);
                    let retryRequest = newRequest.clone({ headers });
                    return next.handle(retryRequest);
                  });
                } else {
                  this.route.navigate(['/tabs/login']);
                }
              } else {
                return Observable.throw(err.statusText);
              }
          } else {
              return Observable.throw(err.statusText);
          }
      }));
  }))
}

Solution

  • I'm not absolutely sure as to why your inner subscription isn't triggering but I'd stab a guess that RxJS is cancelling it because it's in a disposable section of code.

    catchError expects an Observable be returned, but you're not returning anything (TypeScript should warn about this, but it's slipped through the cracks for some reason).

    The following is probably a better approach. The inner Observable is being subscribed to by catchError using switchMap.

    intercept (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        this.presentLoading();
        const headerSettings = req.headers.keys().reduce((acc, cur) => {
            acc[cur] = req.headers.getAll(cur);
            return acc;
        }, {});
        return fromPromise(this.storage.get('userdata')).pipe(mergeMap((token: any) => {
            if(token)
            headerSettings["Authorization"] = token.access_token;
            let headers = new HttpHeaders(headerSettings),
            newRequest = req.clone({ headers });
            return next.handle(newRequest)
            .pipe(catchError((err: any) => {
                if (err instanceof HttpErrorResponse) {
                    // token is expired refresh and try again
                    if (err.status === 401) {
                        if(token && token.refresh_token) {
                        return this.login.refresh(token.refresh_token).pipe(
                            switchMap((data: any) => {
                            if (data.data)
                                headerSettings['Authorization'] =
                                    data.data.access_token;
                            headers = new HttpHeaders(
                                headerSettings
                            );
                            let retryRequest = newRequest.clone({
                                headers,
                            });
                            return next.handle(retryRequest);
                        }));
                        } else {
                        this.route.navigate(['/tabs/login']);
                        }
                    } else {
                        return Observable.throw(err.statusText);
                    }
                } else {
                    return Observable.throw(err.statusText);
                }
            }));
        }))
    }