In my Angular2 application I want to be redirected to the login page whenever I get a 401 response during an Ajax call. Therefore I want to intercept all Ajax calls and check for the response code. In addition to that I also want to set a couple of default request headers for each Ajax call. The code below shows an interceptor for angular2 http requests.

Angular2 Http Interceptor using Typescript

Updated 05/16/16: Angular2 RC1 – All packages moved to @angular instead of angular2

Angular2 Http Interceptor import {bootstrap} from '@angular/platform-browser-dynamic'; import {provide} from '@angular/core'; import {HTTP_PROVIDERS, Http, Request, RequestOptionsArgs, Response, XHRBackend, RequestOptions, ConnectionBackend, Headers} from '@angular/http'; import {ROUTER_PROVIDERS, Router} from '@angular/router'; import {LocationStrategy, HashLocationStrategy} from '@angular/common'; import { Observable } from 'rxjs/Observable'; import * as _ from 'lodash' import {MyApp} from './app/my-app'; class HttpInterceptor extends Http { constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private _router: Router) { super(backend, defaultOptions); } request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> { return this.intercept(super.request(url, options)); } get(url: string, options?: RequestOptionsArgs): Observable<Response> { return this.intercept(super.get(url,options)); } post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> { return this.intercept(super.post(url, body, this.getRequestOptionArgs(options))); } put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> { return this.intercept(super.put(url, body, this.getRequestOptionArgs(options))); } delete(url: string, options?: RequestOptionsArgs): Observable<Response> { return this.intercept(super.delete(url, options)); } getRequestOptionArgs(options?: RequestOptionsArgs) : RequestOptionsArgs { if (options == null) { options = new RequestOptions(); } if (options.headers == null) { options.headers = new Headers(); } options.headers.append('Content-Type', 'application/json'); return options; } intercept(observable: Observable<Response>): Observable<Response> { return observable.catch((err, source) => { if (err.status == 401 && !_.endsWith(err.url, 'api/auth/login')) { this._router.navigate(['/login']); return Observable.empty(); } else { return Observable.throw(err); } }); } } bootstrap(MyApp, [ HTTP_PROVIDERS, ROUTER_PROVIDERS, provide(LocationStrategy, { useClass: HashLocationStrategy }), provide(Http, { useFactory: (xhrBackend: XHRBackend, requestOptions: RequestOptions, router: Router) => new HttpInterceptor(xhrBackend, requestOptions, router), deps: [XHRBackend, RequestOptions, Router] }) ]) .catch(err => console.error(err)); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 import { bootstrap } from '@angular/platform-browser-dynamic' ; import { provide } from '@angular/core' ; import { HTTP_PROVIDERS , Http , Request , RequestOptionsArgs , Response , XHRBackend , RequestOptions , ConnectionBackend , Headers } from '@angular/http' ; import { ROUTER_PROVIDERS , Router } from '@angular/router' ; import { LocationStrategy , HashLocationStrategy } from '@angular/common' ; import { Observable } from 'rxjs/Observable' ; import * as _ from 'lodash' import { MyApp } from './app/my-app' ; class HttpInterceptor extends Http { constructor ( backend : ConnectionBackend , defaultOptions : RequestOptions , private _router : Router ) { super ( backend , defaultOptions ) ; } request ( url : string | Request , options ? : RequestOptionsArgs ) : Observable < Response > { return this . intercept ( super . request ( url , options ) ) ; } get ( url : string , options ? : RequestOptionsArgs ) : Observable < Response > { return this . intercept ( super . get ( url , options ) ) ; } post ( url : string , body : string , options ? : RequestOptionsArgs ) : Observable < Response > { return this . intercept ( super . post ( url , body , this . getRequestOptionArgs ( options ) ) ) ; } put ( url : string , body : string , options ? : RequestOptionsArgs ) : Observable < Response > { return this . intercept ( super . put ( url , body , this . getRequestOptionArgs ( options ) ) ) ; } delete ( url : string , options ? : RequestOptionsArgs ) : Observable < Response > { return this . intercept ( super . delete ( url , options ) ) ; } getRequestOptionArgs ( options ? : RequestOptionsArgs ) : RequestOptionsArgs { if ( options == null ) { options = new RequestOptions ( ) ; } if ( options . headers == null ) { options . headers = new Headers ( ) ; } options . headers . append ( 'Content-Type' , 'application/json' ) ; return options ; } intercept ( observable : Observable < Response > ) : Observable < Response > { return observable . catch ( ( err , source ) = > { if ( err . status == 401 && !_.endsWith(err.url, 'api/auth/login')) { this._router.navigate(['/login']); return Observable . empty ( ) ; } else { return Observable . throw ( err ) ; } } ) ; } } bootstrap ( MyApp , [ HTTP_PROVIDERS , ROUTER_PROVIDERS , provide ( LocationStrategy , { useClass : HashLocationStrategy } ) , provide ( Http , { useFactory : ( xhrBackend : XHRBackend , requestOptions : RequestOptions , router : Router ) = > new HttpInterceptor ( xhrBackend , requestOptions , router ) , deps : [ XHRBackend , RequestOptions , Router ] } ) ] ) . catch ( err = > console . error ( err ) ) ;

In Angular2 it is possible to provide a different default implementation for a particular class.

You can provide these “new” default implementations by providing the implementations in the second parameter of the bootstrap function e.g.

provide(LocationStrategy, { useClass: HashLocationStrategy }), 1 provide ( LocationStrategy , { useClass : HashLocationStrategy } ) ,

This tells Angular to use the HashLocationStrategy class as default implementation for LocationStrategy.

I simply want to provide a new implementation for the Http class, which intercepts all calls and checks if the http status code is 401. Since Http needs a couple of parameters from the dependency injection I had to provide a factory function for my class.

provide(Http, { useFactory: (xhrBackend: XHRBackend, requestOptions: RequestOptions, router: Router) => new HttpInterceptor(xhrBackend, requestOptions, router), deps: [XHRBackend, RequestOptions, Router] }) 1 2 3 4 5 6 provide ( Http , { useFactory : ( xhrBackend : XHRBackend , requestOptions : RequestOptions , router : Router ) = > new HttpInterceptor ( xhrBackend , requestOptions , router ) , deps : [ XHRBackend , RequestOptions , Router ] } )

I extended the original Http class, overrode alls request methods and checked for the response code. The original constructor of Http only has 2 parameters. I simply added another one to Router in order to make a redirect in case of a 401 response code.

Each request function is wrapped by a call to an interceptor function e.g. for the get method:

get(url: string, options?: RequestOptionsArgs): Observable<Response> { return this.intercept(super.get(url,options)); } 1 2 3 get ( url : string , options ? : RequestOptionsArgs ) : Observable <Response> { return this . intercept ( super . get ( url , options ) ) ; }

In the interceptor function itself, I check for the response code and do a redirect to the login page if the user is not authenticated.

intercept(observable: Observable<Response>): Observable<Response> { return observable.catch((err, source) => { if (err.status == 401 && !_.endsWith(err.url, 'api/auth/login')) { this._router.navigate(['Login']); return Observable.empty(); } else { return Observable.throw(err); } }); } 1 2 3 4 5 6 7 8 9 10 11 intercept ( observable : Observable <Response> ) : Observable <Response> { return observable . catch ( ( err , source ) = > { if ( err . status == 401 && !_.endsWith(err.url, 'api/auth/login')) { this._router.navigate(['Login']); return Observable . empty ( ) ; } else { return Observable . throw ( err ) ; } } ) ; }

In my example I specifically excluded the login request url from that check. When I submit a wrong username password combination I also get a 401 in return.

In the getRequestOptionArgs I also set ‘Content-Type’ to ‘application/json’ for each request. Since I am working on a single page application all my requests will be in json.

Summary

This article shows how a Http request interceptor can be implemented in Angular2. If you found a simpler way of doing this, please let me know.