Matthew
Matthew

Reputation: 3071

Angular 5 HttpInterceptor Retry Request

How can an Angluar 5 HttpInterceptor retry a request on error?

The Angular docs don't show an example of an HttpInterceptor retry: https://angular.io/guide/http https://angular.io/api/common/http/HttpInterceptor

Note that there is a retry on the HttpClient object. This is NOT helpful in this case.

Psuedo logic I'm trying to achieve: Send request IF error response THEN change the request and retry the request.

This HttpInterceptor successfully runs the request and catches the error but doesn't retry the request.

export class AuthInterceptor implements HttpInterceptor {
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        return next
            .handle(req)
            .do(event => {
            }, (err: any) => {
                let reqRepeat = req.clone(); // For now, keep it simple. Don't change original request.
                return next.handle(req); // Retry request. THIS DOESN'T SEEM TO DO ANYTHING!
            })
    }
};

Upvotes: 8

Views: 10239

Answers (2)

Arpit Singh
Arpit Singh

Reputation: 416

I always use this code to authenticate, so i will use subjects to implement this logic

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpErrorResponse } from '@angular/common/http';
import { AuthService } from '../services/auth.service';
import { Observable, throwError, BehaviorSubject } from 'rxjs';
import { catchError, filter, take, switchMap } from 'rxjs/operators';

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

  private isRefreshing = false;
  private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);

  constructor(public authService: AuthService) { }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    if (this.authService.getJwtToken()) {
      request = this.addToken(request, this.authService.getJwtToken());
    }

    return next.handle(request).pipe(catchError(error => {
      if (error instanceof HttpErrorResponse && error.status === 401) {
        return this.handle401Error(request, next);
      } else {
        return throwError(error);
      }
    }));
  }

  private addToken(request: HttpRequest<any>, token: string) {
    return request.clone({
      setHeaders: {
        'Authorization': `Bearer ${token}`
      }
    });
  }

  private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
    if (!this.isRefreshing) {
      this.isRefreshing = true;
      this.refreshTokenSubject.next(null);

      return this.authService.refreshToken().pipe(
        switchMap((token: any) => {
          console.log('Token refreshed');
          this.isRefreshing = false;
          this.authService.saveAccessToken(token['access']);
          this.refreshTokenSubject.next(token['access']);
          return next.handle(this.addToken(request, token['access']));
        }),catchError(error => {
          console.log('hi88888888888888');
          if (error instanceof HttpErrorResponse && error.status === 401) {
            this.authService.logout();
            return
          } else {
            return throwError(error);
          }
        }));

    } else {
      return this.refreshTokenSubject.pipe(
        filter(token => token != null),
        take(1),
        switchMap(jwt => {
          console.log(jwt);
          return next.handle(this.addToken(request, jwt));
        }));
    }
  }
}

Upvotes: 7

Leandro Lima
Leandro Lima

Reputation: 1164

The rxjs 'do' operator does not modify the observer. Returning the 'next.handle(...)' should not work.

Try to use the 'catch' operator instead.

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).catch(() => {
      const newReq = req.clone();
      return next.handle(newReq);
    });
  }

Do not forget to import the catch operator:

import 'rxjs/add/operator/catch';

Upvotes: 7

Related Questions