58

In angularjs, we have http interceptor

$httpProvider.interceptors.push('myHttpInterceptor');

with which we can hook into all http calls, and show or hide loading bars, do logging, etc..

What is the equivalent in angular2?

Pardeep Jain
  • 84,110
  • 37
  • 165
  • 215
Vikram Babu Nagineni
  • 3,411
  • 6
  • 25
  • 34

10 Answers10

62

As @Günter pointed it out, there is no way to register interceptors. You need to extend the Http class and put your interception processing around HTTP calls

First you could create a class that extends the Http:

@Injectable()
export class CustomHttp extends Http {
  constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
    super(backend, defaultOptions);
  }

  request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
    console.log('request...');
    return super.request(url, options).catch(res => {
      // do something
    });        
  }

  get(url: string, options?: RequestOptionsArgs): Observable<Response> {
    console.log('get...');
    return super.get(url, options).catch(res => {
      // do something
    });
  }
}

and register it as described below:

bootstrap(AppComponent, [HTTP_PROVIDERS,
    new Provider(Http, {
      useFactory: (backend: XHRBackend, defaultOptions: RequestOptions) => new CustomHttp(backend, defaultOptions),
      deps: [XHRBackend, RequestOptions]
  })
]);

The request and requestError kinds could be added before calling the target methods.

For the response one, you need to plug some asynchronous processing into the existing processing chain. This depends on your need but you can use operators (like flatMap) of Observable.

Finally for the responseError one, you need to call the catch operator on the target call. This way you will be notified when an error occurs in the response.

This links could help you:

Stefan Falk
  • 23,898
  • 50
  • 191
  • 378
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
19

update

The new HttpClient module introduced in Angular 4.3.0 supports interceptors https://github.com/angular/angular/compare/4.3.0-rc.0...4.3.0

feat(common): new HttpClient API HttpClient is an evolution of the existing Angular HTTP API, which exists alongside of it in a separate package, @angular/common/http. This structure ensures that existing codebases can slowly migrate to the new API.

The new API improves significantly on the ergonomics and features of the legacy API. A partial list of new features includes:

  • Typed, synchronous response body access, including support for JSON body types
  • JSON is an assumed default and no longer needs to be explicitly parsed
  • Interceptors allow middleware logic to be inserted into the pipeline
  • Immutable request/response objects
  • Progress events for both request upload and response download
  • Post-request verification & flush based testing framework

original

Angular2 doesn't have (yet) interceptors. You can instead extend Http, XHRBackend, BaseRequestOptions or any of the other involved classes (at least in TypeScript and Dart (don't know about plain JS).

See also

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
12

There's an implementation for a Http @angular/core-like service in this repository: https://github.com/voliva/angular2-interceptors

You just declare the provider for that service on bootstrap, adding any interceptors you need, and it will be available for all the components.

import { provideInterceptorService } from 'ng2-interceptors';

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...,
    HttpModule
  ],
  providers: [
    MyHttpInterceptor,
    provideInterceptorService([
      MyHttpInterceptor,
      /* Add other interceptors here, like "new ServerURLInterceptor()" or
         just "ServerURLInterceptor" if it has a provider */
    ])
  ],
  bootstrap: [AppComponent]
})
olivarra1
  • 3,269
  • 3
  • 23
  • 34
11

DEPRICATED SINCE Angular 4.3 (HttpInterCeptors are Back in 4.3)

You can create your own custom HTTP Class and use rxjs Subject Service to reuse your custom Http Class and implement your behaviors in a custom class.

Implementation of your Custom Http Class with "HttpSubjectService" which contains some rxjs Subjects.

import { Injectable } from '@angular/core';
import { Http, ConnectionBackend, Request, RequestOptions, RequestOptionsArgs, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';


import { HttpSubjectService } from './httpSubject.service';


@Injectable()
export class CustomHttp extends Http {
   constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private httpSubjectService: HttpSubjectService) {
       super(backend, defaultOptions);

       //Prevent Ajax Request Caching for Internet Explorer
       defaultOptions.headers.append("Cache-control", "no-cache");
       defaultOptions.headers.append("Cache-control", "no-store");
       defaultOptions.headers.append("Pragma", "no-cache");
       defaultOptions.headers.append("Expires", "0");
   }

   request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
       //request Start;
       this.httpSubjectService.addSpinner();
       return super.request(url, options).map(res => {
           //Successful Response;
           this.httpSubjectService.addNotification(res.json());
           return res;
       })
           .catch((err) => {
               //Error Response.
               this.httpSubjectService.removeSpinner();
               this.httpSubjectService.removeOverlay();

               if (err.status === 400 || err.status === 422) {
                   this.httpSubjectService.addHttp403(err);
                   return Observable.throw(err);
               } else if (err.status === 500) {
                   this.httpSubjectService.addHttp500(err);
                   return Observable.throw(err);
               } else {
                   return Observable.empty();
               }
           })
           .finally(() => {
               //After the request;
               this.httpSubjectService.removeSpinner();
           });
   }
}

Custom module to register your CustomHttp class - here you overwrite the default Http implementation from Angular with your own CustomHttp Implementation.

import { NgModule, ValueProvider } from '@angular/core';
import { HttpModule, Http, XHRBackend, RequestOptions } from '@angular/http';

//Custom Http
import { HttpSubjectService } from './httpSubject.service';
import { CustomHttp } from './customHttp';

@NgModule({
    imports: [ ],
    providers: [
        HttpSubjectService,
        {
           provide: Http, useFactory: (backend: XHRBackend, defaultOptions: RequestOptions, httpSubjectService: HttpSubjectService) => {
                return new CustomHttp(backend, defaultOptions, httpSubjectService);
            },
            deps: [XHRBackend, RequestOptions, HttpSubjectService]
        }
    ]
})
export class CustomHttpCoreModule {

    constructor() { }
}

now we need the HttpSubjectService Implementation where we can SubScribe to our rxjs Subjects when they get called with the "next" statement.

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class HttpSubjectService {
    //https://github.com/ReactiveX/rxjs/blob/master/doc/subject.md
    //In our app.component.ts class we will subscribe to this Subjects
    public notificationSubject = new Subject();
    public http403Subject = new Subject();
    public http500Subject = new Subject();
    public overlaySubject = new Subject();
    public spinnerSubject = new Subject();

    constructor() { }

    //some Example methods we call in our CustomHttp Class
    public addNotification(resultJson: any): void {
        this.notificationSubject.next(resultJson);
    }

    public addHttp403(result: any): void {
        this.http403Subject.next(result);
    }

    public addHttp500(result: any): void {
        this.http500Subject.next(result);
    }

    public removeOverlay(): void {
        this.overlaySubject.next(0);
    }

    public addSpinner(): void {
        this.spinnerSubject.next(1);
    }

    public removeSpinner(): void {
        this.spinnerSubject.next(-1);
    }
}

to call your custom Implementations we need to Subscribe to the Subjects in the e.g. "app.component.ts".

import { Component } from '@angular/core';
import { HttpSubjectService } from "../HttpInterception/httpSubject.service";
import { Homeservice } from "../HttpServices/home.service";

@Component({
    selector: 'app',
    templateUrl: './app.component.html',
})
export class AppComponent {
    private locals: AppLocalsModel = new AppLocalsModel();

    constructor(private httpSubjectService : HttpSubjectService, private homeService : Homeservice) {}

    ngOnInit(): void {
        this.notifications();
        this.httpRedirects();
        this.spinner();
        this.overlay();
    }

    public loadServiceData(): void {
        this.homeService.getCurrentUsername()
            .subscribe(result => {
                this.locals.username = result;
            });
    }

    private overlay(): void {
        this.httpSubjectService.overlaySubject.subscribe({
            next: () => {
              console.log("Call Overlay Service");
            }
        });
    }

    private spinner(): void {
        this.httpSubjectService.spinnerSubject.subscribe({
            next: (value: number) => {
              console.log("Call Spinner Service");
            }
        });
    }

    private notifications(): void {
        this.httpSubjectService.notificationSubject.subscribe({
            next: (json: any) => {
                console.log("Call Notification Service");
            }
        });
    }

    private httpRedirects(): void {
        this.httpSubjectService.http500Subject.subscribe({
            next: (error: any) => {
                console.log("Navigate to Error Page");
            }
        });

        this.httpSubjectService.http403Subject.subscribe({
            next: (error: any) => {
                console.log("Navigate to Not Authorized Page");
            }
        });
    }
}


class AppLocalsModel {
    public username : string = "noch nicht abgefragt";
}

SINCE ANGULAR 4.3 you can Use InterCeptors

In Angular 4.3 you have native Interceptors where you can implement your own stuff like a redirect for server error 500

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

@Injectable()
export class SxpHttp500Interceptor implements HttpInterceptor {

  constructor(public router: Router) { }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
      return next.handle(req).do(evt => { }).catch(err => {
          if (err["status"]) {
              if (err.status === 500) {
                  this.router.navigate(['/serverError', { fehler: JSON.stringify(err) }]);
              }
          }
          return Observable.throw(err);
      });
  }
}

you need to Register this in your core module in the providers Array

import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { Router } from '@angular/router';
import { SxpHttp500Interceptor } from "./sxpHttp500.interceptor";
 ....

providers: [
    {
        provide: HTTP_INTERCEPTORS, useFactory: (router: Router) => { return new SxpHttp500Interceptor(router) },
        multi: true,
        deps: [Router]
    }
]
squadwuschel
  • 3,328
  • 3
  • 34
  • 45
8

With the Angular 4.3.1 release, there's now an interface called HttpInterceptor.

Here's the link to the docs: https://angular.io/api/common/http/HttpInterceptor

Here's an implementation sample.


This would be the interceptor class implementation.

Is basically written as any other service:

@Injectable()
export class ExceptionsInterceptor implements HttpInterceptor {
    constructor(
        private logger: Logger,
        private exceptionsService: ExceptionsService,
        private notificationsService: NotificationsService
    ) { }
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        return next.handle(request)
            .do((event) => {
                // Do nothing here, manage only errors
            }, (err: HttpErrorResponse) => {
                if (!this.exceptionsService.excludeCodes.includes(err.status)) {
                    if (!(err.status === 400 && err.error['_validations'])) {
                        this.logger.error(err);
                        if (!this.notificationsService.hasNotificationData(err.status)) {
                            this.notificationsService.addNotification({ text: err.message, type: MessageColorType.error, data: err.status, uid: UniqueIdUtility.generateId() });
                        }
                    }
                }
            });
    }
}

Then since you'll treat this like a normal service, you have to add this line inside your app module's providers:

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

Hope it can help.

Caius
  • 2,084
  • 6
  • 31
  • 47
  • 2
    And, where is the implementation? – Lin Du Aug 08 '17 at 06:05
  • 2
    Useful imports: `import { HTTP_INTERCEPTORS } from "@angular/common/http";`, `import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from "@angular/common/http";` – Birchlabs Oct 05 '17 at 12:11
  • NotificationsService is not working globaly..Any suggestion? https://github.com/flauc/angular2-notifications – sangram parmar Jan 23 '18 at 15:01
3

Angular 4.3 now supports Http interceptor out-of-the-box. Check it out how to use them: https://ryanchenkie.com/angular-authentication-using-the-http-client-and-http-interceptors

Martino Bordin
  • 1,412
  • 1
  • 14
  • 29
0

I have released interceptor with following node module. We was create this module for our internal purpose finally we released in npm package manager npm install angular2-resource-and-ajax-interceptor https://www.npmjs.com/package/angular2-resource-and-ajax-interceptor

Rajan
  • 31
  • 1
  • 4
0

As @squadwuschel pointed out, work is underway to get this functionality into @angular/http. This will be in the form of a new HttpClient API.

See https://github.com/angular/angular/pull/17143 for more details and current status.

rdukeshier
  • 99
  • 4
0

Try Covalent from Teradata, they provides lots of extensions for Angular and Angular Material.

Check HTTP part, it provides the missing http interceptor in Angular and RESTService(similar to restangular).

I have implemented JWT token authentication via Covalent HTTP in my sample, Please check here.

https://github.com/hantsy/angular2-material-sample/blob/master/src/app/core/auth-http-interceptor.ts

Read my development notes for it, Handle token based Authentication via IHttpInterceptor.

Hantsy
  • 8,006
  • 7
  • 64
  • 109
  • BTW, Angular 4.3 was just released, it includes the new Http Client( [#37797e2](https://github.com/angular/angular/commit/37797e2)), I think we do not need the 3rd party tools or custom HTTP now. – Hantsy Jul 15 '17 at 02:14
  • 1
    This might help: https://modewagon.wordpress.com/2017/09/13/angular-4-http-interceptor/ – Victor Odiah Sep 13 '17 at 14:44
0

Angular2 donot support httpinterceptor like angular1

Here is awesome example of use of httpinterceptor in angular2.

https://github.com/NgSculptor/ng2HttpInterceptor

Er. Bahuguna Goyal
  • 192
  • 1
  • 3
  • 10