Cover image for Angular2でHTTP Interceptorを使いたい
angularangular2

Angular2でHTTP Interceptorを使いたい

April 11, 2016

4 min read

mitsuruogMitsuru Ogawa

Way of httpInterceptor in Angular 2

4/10 に開催されたAngular 2 ハンズオンのチューターとして参加してきました。
チューターしている合間に、Angular2 での HttpIntercepor のやり方を調べてたので、その辺りを紹介します。

ついでに LT してきました。LT の資料はこちらです。

Angular2 HttpInterceptor Needed
https://gist.github.com/mitsuruog/6f7f0ca3f546b245bccdd3ebc14375d8

HttpInterceptor とは

HttpInterceptorとは、XHR(つまり Ajax)に関連する横断的機能(cross-cutting feature)を分離するためのものです。

Controller などの後続処理から、XHR 通信時に発生する例外処理などを分離してHttpInterceptorで一括処理します。 Angular1 では、HttpInterceptorを使うことで綺麗に分離することができました。

refs: AngularJS: API: $http

Angular2 では簡単にはできない

Angular2 でも簡単に実現できると考えていたのですが、思ったより面倒でした。 公式リポジトリの Issue にて実現方法について議論されていました。(めっちゃ長いです)

RFC: Http interceptors and transformers · Issue #2684 · angular/angular

Angualr2 での HttpInterceptor の実現方法

以下の手順で実現できます。

  1. Httpを継承したCustomHttpを作成する。
  2. bootstrapにて、既存のHttpプロバイダを Ovarride する。

では順に見て行きましょう。

CustomHttpを作成する

まず、CustomHttpを作成します。Httpの API を 1 つ 1 つ Warp します。
例外が発生した場合は、catchで捕捉して private 関数のhandleResponseErrorで一括処理させるようにしています。

custom-http.service.ts

import {
  Http,
  ConnectionBackend,
  RequestOptions,
  Request,
  RequestOptionsArgs,
  Response,
} from "angular2/http";
import { Observable } from "rxjs/Observable";

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

  request(
    url: string | Request,
    options?: RequestOptionsArgs
  ): Observable<Response> {
    return super
      .request(url, options)
      .catch((res: Response) => this.handleResponseError(res));
  }

  get(url: string, options?: RequestOptionsArgs): Observable<Response> {
    return super
      .get(url, options)
      .catch((res: Response) => this.handleResponseError(res));
  }

  // ...長いので省略

  //
  // Here's to handle error stuff
  //
  private handleResponseError(res: Response) {
    if (res.status === 401) {
      // do something
    } else if (res.status === 500) {
      // do something
    }
    return Observable.throw(res);
  }
}

Httpを上書きする。

つづいて、bootstrap時にHttpCustomHttpで上書きします。 次のコードは、provideを利用して、Angular2 が DI を処理する際にインスタンスを生成する方法を変更しています。

main.ts

import { provide } from "angular2/core";
// RxJS本体のObservableを利用するための設定
import { bootstrap } from "angular2/platform/browser";
import "rxjs/Rx";

import { AppComponent } from "./app.component";
import { CustomHttp } from "./common/services/custom-http.service";

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

まとめ

Angular2 でもHttpInterceptorを実現できそうですが、少し面倒でした。

こちらにcustom-http.service.tsのコード置いておきます。(しばらくはこのままで使えるはず。。。)

custom-http.service.ts

(追記) LT ではnew Providor()としていましたが、 @laco0416さんから、 Providorを Warp しているprovideを利用した方が破壊的変更が起きにくいとアドバイスいただき変更しました。ありがとうございます!!