100

How to add multiple, independent HTTP interceptors to an Angular 4 application?

I tried to add them by extending the providers array with more than one interceptors. But only the last one is actually executed, Interceptor1 is ignored.

@NgModule({
  declarations: [ /* ... */ ],
  imports: [ /* ... */ HttpModule ],
  providers: [
    {
      provide: Http,
      useFactory: (xhrBackend: XHRBackend, requestOptions: RequestOptions) =>
        new Interceptor1(xhrBackend, requestOptions),
      deps: [XHRBackend, RequestOptions],
    },
    {
      provide: Http,
      useFactory: (xhrBackend: XHRBackend, requestOptions: RequestOptions) =>
        new Interceptor2(xhrBackend, requestOptions),
      deps: [XHRBackend, RequestOptions]
    },
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

I could obviously combine them into a single Interceptor class and that should work. However, I would like to avoid that as these interceptors have completely different purposes (one for error handling, one to show a loading indicator).

So how can I add multiple interceptors?

str
  • 42,689
  • 17
  • 109
  • 127

1 Answers1

196

Http doesn't allow to have more than one custom implementation. But as @estus mentioned the Angular team has added a new HttpClient service recently (release 4.3) which supports multiple interceptors concept. You don't need to extend the HttpClient as you do with the old Http. You can provide an implementation for HTTP_INTERCEPTORS instead which can be an array with the 'multi: true' option:

import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http';
...

@NgModule({
  ...
  imports: [
    ... ,
    HttpClientModule
  ],
  providers: [
    ... ,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: InterceptorOne,
      multi: true,
    },
    {
      provide: HTTP_INTERCEPTORS,
      useClass: InterceptorTwo,
      multi: true,
    }
  ],
  ...
})

Interceptors:

import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
...

@Injectable()
export class InterceptorOne implements HttpInterceptor {

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.log('InterceptorOne is working');
    return next.handle(req);
  }
}

@Injectable()
export class InterceptorTwo implements HttpInterceptor {

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.log('InterceptorTwo is working');
    return next.handle(req);
  }
}

This server call will print both interceptors' log messages:

import {HttpClient} from '@angular/common/http';
...

@Component({ ... })
export class SomeComponent implements OnInit {

  constructor(private http: HttpClient) {}

  ngOnInit(): void {
    this.http.get('http://some_url').subscribe();
  }
}
hiper2d
  • 2,814
  • 1
  • 18
  • 14
  • 4
    Is there any way to tell `api` call can be intercept by only one `interceptor` ? or by any conditions ? – k11k2 Mar 07 '18 at 10:30
  • @k11k2 and for everyone searching, here is a question and answer about this: https://stackoverflow.com/questions/45781379/how-to-add-httpclient-interceptors-conditionally-in-angular I admit I'm still a bit confused about it. – trollkotze Mar 27 '18 at 18:15
  • Why has to be @Injectable()? It works without @Injectable() for me – makkasi Aug 03 '18 at 06:35
  • 1
    @makkasi: Need to add@Injectable if the interceptor class needs to do any dependency injection of its own. In the given example, it is not required – Jinto Dec 05 '18 at 23:49
  • How to fix about interceptors ordering? – AmirReza-Farahlagha Sep 11 '19 at 07:25
  • 2
    @AmirReza-Farahlagha Interceptors are called in the order in which they are provided – hiper2d Sep 11 '19 at 17:35