wake-up-neo.com

Angular 5 HTTP Interceptors Fehler beim Einspeisen von Service

Bei der Verwendung benutzerdefinierter HttpInterceptors in angle 5+ erhalte ich das folgende merkwürdige Abhängigkeitseinspritzverhalten.

Der folgende vereinfachte Code funktioniert gut:

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

        intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
            const token = this.auth.getToken();
            return next.handle(req);
        }
    }
    export class AuthService {
        token: string;
        constructor() {
          console.log('AuthService.constructor');
        }
    }

JEDOCH....

Wenn AuthService eine oder mehrere Abhängigkeiten hat, z.

   export class AuthService {
      token: string;
      constructor(private api: APIService) {
         console.log('AuthService.constructor');
      }
   }

angle versucht wiederholt, neue Instanzen von AuthService zu erstellen, bis folgende Fehler angezeigt werden:

Das Protokoll zeigt die AuthService.constructor-Nachricht ~ 400 Mal an

und

Cannot instantiate cyclic dependency! HTTP_INTERCEPTORS ("[ERROR ->]"): in NgModule AppModule

und 

app.component.html: 44 ERROR RangeError: Maximale Aufrufstackgröße übertroffen

Ich habe dann versucht, den Dienst mithilfe der Injector-Klasse zu injizieren. 

 export class AuthService {
      token: string;
      api: APIService;
      constructor(private injector: Injector) {
         this.api = this.injector.get(APIService);
         console.log('AuthService.constructor');
      }
   }

aber den gleichen Fehler erhalten (maximale Aufrufstackgröße).

Die APIService ist ein einfacher Dienst, der nur die HttpClient in seinen Konstruktor einfügt.

@Injectable()
export class APIService {
    constructor(private http: HttpClient) {}
}

Wenn ich die AuthService mit der Injector in den Interceptor injiziere, wird der Fehler nicht mehr angezeigt, der AuthService wird jedoch mehr als 200 Mal instanziiert:

export class AuthInterceptor implements HttpInterceptor {
    auth: AuthService;
    constructor(private injector: Injector) {}
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
           this.auth = this.auth || this.injector.get(AuthService);
           const token = this.auth.getToken();
           return next.handle(req);
        }
    }

Betrachtet man die offizielle Dokumentation und andere Beispiele, scheint es technisch möglich zu sein, Dienste in die HTTP-Interceptors einzuspeisen. Gibt es Einschränkungen oder andere Einstellungen, die möglicherweise fehlen?

6
Yani

Es stellt sich also heraus, dass der in den HTTP-Interceptor eingebundene Dienst von HttpClient abhängig ist, was zu einer zyklischen Abhängigkeit führt.

Da meine AuthService eine Mischung aus allen verschiedenen Logiken war (Anmelden/Abmelden, Weiterleiten des Benutzers, Speichern/Laden von Token, Durchführen von API-Aufrufen), habe ich den für die Abfangjäger benötigten Teil in seinen eigenen Dienst (nur die Anmeldeinformationen und Token des Benutzers) aufgeteilt jetzt erfolgreich in den Interceptor injizieren.

export class AuthInterceptor implements HttpInterceptor {
    constructor(private credentials: CredentialsService) {}
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        const token = this.credentials.getToken();
        const api_key = this.credentials.getApiKey();
    }
}

export class CredentialsService {
    token: string;
    user: IUser;
    constructor(private http: HttpClient) {
        this.loadCredentialsFromStorage();
    }
}

Das scheint gut zu funktionieren. Hoffe das hilft jemandem.

5
Yani

Update Ende Januar 2018

Angular Team hat dieses Problem in Angular 5.2.3 behoben, das am 31. Januar 2018 veröffentlicht wurde. Nach der Aktualisierung der Winkelversion können Sie Services einbinden, die HTTPClient wie üblich im Konstruktor verwenden

Fehlerbehebung

common: HttpInterceptors dürfen HttpClient (# 19809) (ed2b717) injizieren, schließt # 18224

aus Angular changelog

6
Gwidon

sie müssen Injector in den Konstruktor einfügen und AuthService über den Injektor injizieren

export class AuthInterceptor implements HttpInterceptor {
            constructor(private inj: Injector) {}

            intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
                const auth = this.inj.get(AuthService);
                const token = this.auth.getToken();
                return next.handle(req);
            }
        }

import nicht vergessen

import {Injector} from '@angular/core';
3

Ich habe ein ähnliches Problem mit dem gleichen Design eines Auth-Service und einem Interceptor.

@Injectable() AuthInterceptorService {
    constructor (authApi: AuthApiService) {}
    handle () {...do the job}
}

@Injectable() AuthApiService {
   constructor () {
       // ...do some setup with a request, such as to get current session
       // that leads to an indirect circular between 2 constructors. 
   }

}

In meinem Fall fand ich die Ursache darin, dass ich versuche, eine http-Anfrage im Konstruktor des Auth-Dienstes zu starten. Zu diesem Zeitpunkt scheint der Injektor die Registrierung der Instanz des Auth-Dienstes noch nicht abgeschlossen zu haben, während der http-Client die neue Anforderung erfasst und versucht hat, den Interceptor erneut zu instantiieren, da die vorherige Interceptor-Instanz auch in ihrem Konstruktor auf dem Aufruf-Stack stecken blieb! 

Dieser rekursive Aufruf mit zwei Konstruktoren unterbricht das Singleton-Muster des Injektors und führt zum Stack-Out.

1
Edward Liang

Stellen Sie bei diesem Problem sicher, dass der Dienst, den Sie in Http Interceptor einschleusen, in den Anbietern zusammen mit den HTTP_INTERCEPTORS im Modul hinzugefügt werden muss.

providers: [ AuthService,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: HttpConfigInterceptor,
      multi: true
    }
]
0