HTTP Interceptor Angular

If you are completely new to making HTTP requests in Angular, be sure to see our 5 minute guide to making HTTP requests in Angular.

The Angular HttpInterceptor

The HttpInterceptor interface allows you to modify all incoming/outgoing HTTP requests in your Angular app.

HTTP interceptors are useful for things like caching responses, modifying HTTP headers, and logging information.

The http interceptor is similar to a middleware function in Express or Spring Boot app.

The HttpInterceptor interface was released with Angular v4.3.

angular http interceptor examples:

Here is a basic example of implementing the HttpInterceptor interface:

import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse } from '@angular/common/http';
import { Observable }  from 'rxjs';

@Injectable()
export class MyInterceptorService implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler) {
    //log the request url
    console.log(req.url);
    return next.handle(req);
  }
}

Since HttpInterceptor is an interface, we implement it with our own MyInterceptorService class definition.

In order to correctly implement HttpInterceptor, we must define an intercept() method taking an HttpRequest and HttpHandler as arguments.

While the HttpRequest represents the current HTTP request being processed, the HttpHandler takes the request and transforms it into a stream of HttpEvent. Notice how we must import these classes from the @angular/common/http module to use them in our implementation.

In our example, we log the current req.url before returning next.handle(req). This passes the request to the next interceptor in the chain (you can define as many interceptors as you want) or executes the request if the chain is complete.

Providing the HTTP Interceptor

To use our MyInterceptorService, we must import HTTP_INTERCEPTOR and the service itself. We must also list a provider in our app.module.ts file.

import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { MyInterceptorService} from './my-interceptor.service'
@NgModule({...
  providers: [
    {
      provide:HTTP_INTERCEPTORS,
      useClass: MyInterceptorService,
      multi:true
    }
  ],...

Notice how we list an object in the providers array in @NgModule. We specify to provide the HTTP_INTERCEPTORS using our MyInterceptorService implementation.

We can optionally set multi:true, instructing the provider to inject an array of values. To better understand the benefit of this, check out Pascal Precht's Multi Providers in Angular.

Example: Changing the URL

You can easily modify the headers of an HTTP request using the HTTP interceptor:

@Injectable()
export class MyInterceptorService implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler) {
    const https = req.clone({
      url: req.url.replace('http://', 'https://')
    });
    return next.handle(https)
  }
}

Notice how we call req.clone() to clone the request object req and modify the new request to force https.

We have to clone the request because HttpRequest is immutable. Angular designed it this way to prevent retry attempts from being modified.

Example: Modifying the Headers

@Injectable()
export class MyInterceptorService implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler) {
    const token = "YOUR_AUTH_TOKEN"
    const authReq = req.clone({
      headers: req.headers.set('Authorization', token)
    })
    return next.handle(authReq)
  }
}

Notice how we set a token variable set to YOUR_AUTH_TOKEN. This token should come from a a separate Authorization service interacting with the server, but we've assigned it to YOUR_AUTH_TOKEN for simplicity.

We are able to set the Authorization header via req.headers.set('Authorization', token).

Example: Caching Responses

@Injectable()
export class MyInterceptorService implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler) {
      let cachedUrl: HttpResponse<any> = JSON.parse(localStorage.getItem(req.url));
      return cachedUrl ? Observable.of(new HttpResponse<any>(cachedUrl)) : this.sendRequest(req, next);
  }
  sendRequest(req: HttpRequest<any>, next: HttpHandler) {
    return next.handle(req).do(event => {
      if (event instanceof HttpResponse) {
        localStorage.setItem(req.url, JSON.stringify(event));
      }
    })
  }
}

Our interceptor() function first attempts to retrieve the response from localStorage. If it exists, the cached HttpResponse is returned. This works because we short-circuit the promise chain by returning an observable.

If the cachedUrl doesn't exist yet, we call sendRequest(). This method takes our existing req and next objects and returns next.handle(req) after setting the HttpResponse event in localStorage.

Notice how we utilize localStorage to save the HttpResponse objects. We map these responses to their respective URLs by using the req.url as a key in localStorage.

Notice how we call JSON.parse() and JSON.stringify() to encode/decode the HttpResponse objects. This is because localStorage only stores the string representation of an object.

This is a basic example of implementing a cache using the http interceptor. For a more sophisticated implementation, check out Nicholas Rempel's example.

Angular HTTP Interceptor not Working?

If things aren't working for you, be sure to verify it's not one of these common reasons:

Using @angular/http instead of @angular/common/http

Remember that HttpInterceptor wasn't introduced until 4.3. You must make sure you are referencing the correct http library otherwise the interceptor will not work with your Angular app.

Interceptors provided after HttpClient are ignored

Make sure that you have provided your interceptor(s) before the HttpClient. Otherwise they will be ignored. Providing them in the app.module.ts as demonstrated is a recommended approach.

Order matters!

Angular provides interceptors in the order you provide them. Remember that order matters when providing multiple interceptors.

Conclusion

The HttpInterceptor interface provides an easy way to modify the incoming/outgoing HTTP requests in Angular. You can implement the HttpInterceptor interface to modify request headers, cache requests, log information, and more.

Your thoughts?