web-dev-qa-db-ja.com

Angular 4.3インターセプター-使用方法は?

承認ヘッダーを必要とする新しいアプリを作成中です。通常、私はこの scotch.ioの記事 にあるアプローチと非常によく似たものを使用します。しかし、HTTPインターセプターが新しいHttpClientModuleを介してAngular 4エコシステム内で完全にサポートされるようになり、それらの正確な使用方法に関するドキュメントを見つけようとしています。

(4.3の時点で)これが承認ヘッダーを挿入するためのベストプラクティスであることに誤りがある場合は、提案も受け付けます。私の考えでは、これは最近追加された機能であり、「AngularApproved」メソッドに移行する正当な理由があることを意味します。

7
joshrathke

この回答は、CodeWarriorによってリンクされている 公式ドキュメント から借用しています。

Angularを使用すると、HttpInterceptorを作成できます。

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

@Injectable()
export class NoopInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req);
  }
}

その後、次のようにアプリに統合できます。

import {NgModule} from '@angular/core';
import {HTTP_INTERCEPTORS} from '@angular/common/http';

@NgModule({
  providers: [{
    provide: HTTP_INTERCEPTORS,
    useClass: NoopInterceptor,
    multi: true,
  }],
})
export class AppModule {}

承認ヘッダーを追加するには、変更されたヘッダーを使用してリクエストのクローンを作成します。

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

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(private auth: AuthService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // Get the auth header from the service.
    const authHeader = this.auth.getAuthorizationHeader();
    // Clone the request to add the new header.
    const authReq = req.clone({headers: req.headers.set('Authorization', authHeader)});
    // Pass on the cloned request instead of the original request.
    return next.handle(authReq);
  }
}

インターセプターはチェーンのように機能するため、複数のインターセプターを設定してさまざまなタスクを実行できることに注意してください。

10
John

インターセプターのコンストラクターにAuthServiceを挿入すると、次のエラーが発生しました。

キャッチされないエラー:プロバイダーの解析エラー:循環依存をインスタンス化できません! InjectionToken_HTTP_INTERCEPTORS( "[ERROR->]"):./ AppModule @ -1:-1のNgModuleAppModule内

そのため、コンストラクターに挿入する代わりに、@angular/coreInjectorを使用しましたが、正常に機能しました。トークンをlocalStorageに保存し、基本認証を使用しています。設定する必要があります

Authorization: 'Bearer token_string'

これが私が実装した方法です:

token.interceptor.ts

import {Injectable, Injector} from '@angular/core';

import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {AuthService} from './auth.service';

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

    constructor(private injector: Injector) { }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        const auth = this.injector.get(AuthService);
        if (auth.getToken()) {
            request = request.clone({
                setHeaders: {
                    Authorization: `Bearer ${auth.getToken()}`
                }
            });

        }

        return next.handle(request);
    }
}

AuthServiceのgetToken関数

ここでは、ロジック全体を実装して、ヘッダーまたはトークンのみを取得できます。私の場合、これを呼び出すのはJWTトークン文字列を取得するためだけです。

/**
 * Get jwt token
 * @returns {string}
 */
getToken(): string {
    return localStorage.getItem('token');
}

app.module.ts

TokenInterceptorをインポートします

import {TokenInterceptor} from './pathToTheFile/token.interceptor';

@NgModule配列のproviders:の下に以下を追加します。

providers: [
    {
        provide: HTTP_INTERCEPTORS,
        useClass: TokenInterceptor,
        multi: true
    }
    //, other providers
]
3
Lahar Shah

推奨されるアプローチで私が抱えていた問題は、インターセプターがコンパイル時に認識されている必要があり、明らかにすべて同じモジュール内にあることでした。

実行時に拡張できる1つのインターセプターと一連のハンドラー関数を実装することを選択しました。サービスのインターセプトメソッドがnext()ロジックを処理します。

サービス(基本コード、検証またはメンテナンスなし):

export type HttpHandlerFunction = (req: HttpRequest<any>) => HttpRequest<any>;

@Injectable()
export class HttpInterceptorService implements HttpInterceptor {
    private _handlers: Array<HttpHandlerFunction> = [];

    addHandler(handler: HttpHandlerFunction): void {
        this._handlers.Push(handler);
    }

    intercept(req: HttpRequest<any>, next: HttpHandler):
        Observable<HttpEvent<any>> {
            this._handlers.forEach((handler: HttpHandlerFunction) => {
                req = handler(req);
            })
        return next.handle(req);
    }
}

そして、別のモジュールのいくつかのサービスでの使用法:

constructor(injector: Injector) {

    const interceptorsArray: Array<any> = injector.get(HTTP_INTERCEPTORS),
        interceptor: HttpInterceptorService = interceptorsArray &&
            interceptorsArray.filter((i: any) => i instanceof HttpInterceptorService)[0];
    if (interceptor) {
        interceptor.addHandler((req: HttpRequest<any>) => {
            const accessToken = this.getAccessToken();
            if (accessToken) {
                // doesn't work with direct headers.set, you must clone
                req = req.clone({ headers: req.headers.set('Authorization', accessToken) });
            }
        return req;
    });
}
0
dfl