7

So I created an angular2 module to handle HTTP Intercepting, using a basic interceptor like so:

@Injectable()
export class RequestInterceptor implements HttpInterceptor {
  constructor(private injector: Injector) {}

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const authService = this.injector.get(AuthService);
    if(authService.isAuthenticated()){
      const authReq = request.clone({
        setHeaders: {
          Authorization: `Bearer ${authService.getAccessToken()}`
        }
      });
      let handle = next.handle(authReq).do(event => {
        if(event instanceof HttpResponse){
          if(event.headers.has('Authorization')){
            authService.updateToken(event.headers.get('Authorization').split(' ')[1]);
          }
        }
      });
      return handle;
    }else{
      return next.handle(request);
    }
  }
}

Which will add an authorization header to http requests and update its own header when a new one is sent from the server. Its imported and provided normally like so:

{
  provide: HTTP_INTERCEPTORS,
  useClass: RequestInterceptor,
  multi: true
},

So the auth angular2 module is compiled and imported into my app.module.t, it works great. Until I tried to use it from a child module. The top answer from here: Inherit imports from parent module to child module in Angular2 claims that angular2 wont let you make things available globally to the whole app. Is this correct?

I got it working from the child module by just importing the RequestInterceptor, and setting it up in the providers for the module, but I'd rather not have to do so to make it less cumbersome to use.

Ronin
  • 2,527
  • 2
  • 11
  • 13
  • Providers are accessible from everywhere in your app, you shouldn't be adding them in every module. – nicowernli Feb 12 '18 at 22:50
  • The interceptor in my lazy loaded child module is completely ignored. It only works if I put it in the app.module providers. I only want the interceptor in my child module an no where else. Any ideas? – HGPB May 03 '19 at 13:21

4 Answers4

16

Not the best answer - but check out this bug: https://github.com/angular/angular/issues/20575

Specifically the comment that reads:

You should import the HttpClientModule only once, see docs

I imagine that you are re-importing the HttpClientModule somewhere in your Module tree - likely in another child module. If you just declare it once, in the AppModule (or one if it's imports) then it should start working everywhere. That was my experience anyhow.

That kind of stinks - and feels ripe for causing bugs down the road when another dev imports it in a ChildModule later, and doesn't realize the intercept logic is no longer working. But that seems to be the way it is.

MattW
  • 11,480
  • 4
  • 34
  • 63
  • 1
    Thanks a thousands! Such a simple overlooked thing indeed. They should throw an error in that module to make sure it's only imported once... – CularBytes Jul 11 '20 at 19:51
4

I came across with a similar problem. I got a custom HTTP interceptor for purpose of sending JWT to API and weirdly while some of my components working properly, some of them just rejected by server with 401. After some trial & errors, I read @MattW's answer and realized that there are multiple HttpClientModules imported in my application. I cleared them all and imported HttpClientModule only in the AppModule (root). After that, all is fixed.

0

I had the same issue. Interceptor was not adding a token requests made in lazy loaded modules. Importing HttpClientModule is not the best option, unless you want to override the HttpClientModule instance. If you import the HttpClientModule again, it will override all the interceptors declared in the root module.

Direct quote from angular docs:

To use the same instance of HttpInterceptors for the entire app, import the HttpClientModule only in your AppModule, and add the interceptors to the root application injector . If you import HttpClientModule multiple times across different modules (for example, in lazy loading modules), each import creates a new copy of the HttpClientModule, which overwrites the interceptors provided in the root module.

https://angular.io/api/common/http/HttpInterceptor#usage-notes

-4

The solution is to import HttpClientModule also in the child module

imports: [
  ...
  HttpClientModule 
],
declarations: [...],
providers: [
 { provide: HTTP_INTERCEPTORS, useClass: RequestInterceptor, multi: true }
]
m e
  • 543
  • 5
  • 8