web-dev-qa-db-fra.com

Angular 4.3 Intercepteurs - Comment utiliser?

Je suis en train de créer une nouvelle application nécessitant des en-têtes d'autorisation. J'utilise généralement quelque chose de très similaire à l'approche trouvée dans cet article scotch.io . Mais il m'est apparu que les intercepteurs HTTP sont désormais entièrement pris en charge dans l'écosystème Angular 4 via le nouveau module HttpClientModule et j'essaie de trouver de la documentation sur la manière de les utiliser.

Si je me trompe (à partir de la version 4.3), il s’agit de la meilleure pratique pour l’injection des en-têtes d’autorisation, je serais également ouverte aux suggestions. Je pensais que c'était une fonctionnalité ajoutée récemment, ce qui signifie qu'il y a probablement une bonne raison de migrer vers une méthode "Angular Approved".

6
joshrathke

Cette réponse est empruntée à la documentation officielle associée à CodeWarrior.

Angular vous permet de créer un 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);
  }
}

que vous pouvez ensuite intégrer à votre application comme suit:

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

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

Pour ajouter un en-tête d'autorisation, vous pouvez cloner la demande avec les en-têtes modifiés:

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);
  }
}

Notez que les intercepteurs agissent comme une chaîne, vous pouvez donc configurer plusieurs intercepteurs pour effectuer différentes tâches.

9
John

Injecter AuthService au constructeur de l'Interceptor me donnait cette erreur: 

Erreur non capturée: erreurs d'analyse du fournisseur: impossible d'instancier le cyclique dépendance! InjectionToken_HTTP_INTERCEPTORS ("[ERROR ->]"): dans NgModule AppModule in ./AppModule@-1:-1

Ainsi, au lieu de l'injecter au constructeur, j'ai utilisé Injector de @angular/core et cela a bien fonctionné. Je stocke le jeton dans localStorage et j'utilise l'authentification de base. J'ai besoin de mettre 

Authorization: 'Bearer token_string'

Voici comment j'ai implémenté:  

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);
    }
}

fonction getToken dans AuthService

Ici, vous pouvez implémenter toute la logique pour obtenir l'en-tête ou uniquement le jeton. Ici, dans mon cas, je l’appelle uniquement pour obtenir la chaîne de jeton JWT. 

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

app.module.ts

Importer la TokenInterceptor

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

ajoutez ce qui suit sous @NgModule dans le tableau providers:.

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

Le problème que j'avais avec l'approche recommandée était que les intercepteurs devaient être connus au moment de la compilation et, apparemment, tous dans le même module. 

J'ai opté pour l'implémentation d'un intercepteur et d'une chaîne de fonctions de gestionnaire pouvant être étendues au moment de l'exécution. La méthode d'interception du service prend en charge la logique next ().

Le service (code de base, pas de validations ni de maintenance):

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);
    }
}

Et l'utilisation, dans certains services, dans un module différent:

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