Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change header on HTTP before retrying an Observable

I am using Angular 2 with TypeScript on the front-end. I am trying to implement a http interceptor that is setting the authorization header on each request. If the access token expires I am trying to retry the request, get a new access token with the refresh token and change the header of the current request, before the retry.

How to update the request header in the retryWhen operator?

For example here is the HttpInterceptor:

export class HttpInterceptor extends Http {
    get(url: string, options?: RequestOptionsArgs): Observable<Response> {
        return super.get(url, this.setRequestAuthorizationHeader(options)).retryWhen((errors: any) => this.errorHandler(errors));
    }

    private setRequestAuthorizationHeader(options?: RequestOptionsArgs): RequestOptionsArgs {
        // some checks
        // get accessToken from localStorage
        options.headers.append('Authorization', 'Bearer ' + accessToken);
    }

    private errorHandler(errors) {
        return errors.switchMap((err) => {
        if (err.status === 401) {
            let closedSubject = new Subject();

            this.authenticationService.refreshToken()
                .subscribe(data => {
                    // How to update authorization header? This doesn't work.
                    this.defaultOptions.headers.append('Authorization', 'Bearer ' + data.accessToken);

                    closedSubject.next();
                });

            return <any>closedSubject;
        }
        else {
            return Observable.throw(err.json());
        }
    });
}
}
like image 696
VGeorgiev Avatar asked Oct 17 '22 14:10

VGeorgiev


1 Answers

I would use catch instead of retryWhen as the latter one replay the same observable, and the parameters have already been set.

BTW, your Subject is useless in errorHanlder :

export class HttpInterceptor extends Http {
  get(url: string, options ? : RequestOptionsArgs): Observable < Response > {
    return super.get(url, this.setRequestAuthorizationHeader(options)).catch(errors => this.errorHandler(errors, url, options))
  });
}

private setRequestAuthorizationHeader(options ? : RequestOptionsArgs): RequestOptionsArgs {
  // some checks
  // get accessToken from localStorage
  options.headers.append('Authorization', 'Bearer ' + accessToken);
  return options
}

private errorHandler(err: any, url: string, options ? : RequestOptionsArgs) {
  if (err.status === 401) {
    return this.authenticationService.refreshToken()
      .switchMap(data => {
          // save accessToken to localStorage
          return super.get(url, this.setRequestAuthorizationHeader(options));
      });
  }
  return Observable.throw(err.json());
}

Also note that using state like this.defaultOptions is probably not your best choice, using anobservable would be more appropriate.

like image 64
n00dl3 Avatar answered Nov 15 '22 06:11

n00dl3