web-dev-qa-db-de.com

Wie wird HttpClient in einer statischen Methode oder in einer benutzerdefinierten Klasse injiziert?

Ich möchte angle HttpClient in einer statischen Methode oder Klasse verwenden (in der Klasse kann es nicht als Konstruktorparameter definiert werden).

Ich habe so etwas ausprobiert:

export class SomeNotInjectableService {
  static doSomething() {
    const injector = Injector.create({
      providers: [{provide: HttpClient, deps:[]}]
    });
    const httpClient: HttpClient = injector.get(HttpClient);

    httpClient.request(...); // error Cannot read property 'handle' of undefined
  }
}

dies ist ein Versuch, den Client in der statischen Servicemethode manuell einzuspeisen. Funktioniert nicht Ich bin neugierig, wie man das macht oder wie man den Client in einer normalen Methode injiziert, aber in einer Klasse, die keine Komponente ist.

7
elzoy

Ich bin nicht genau sicher, ob es nicht so funktioniert, wie Sie es versucht haben (wahrscheinlich fehlt etwas, wenn Sie den Injektor erstellen), aber es funktioniert, wenn Sie einen Injektor verwenden

Wenn Sie sich den Code ansehen, der den Fehler auslöst, werden Handler für die Anforderung erwähnt, die in Ihrem Beispiel scheinbar null sind. Möglicherweise registriert Winkel einige interne Handler, wenn der HttpClient auf die "traditionelle" Weise bereitgestellt wird, aber nicht so, wie Sie es tun

// Beginne mit einem Observable.of () der ersten Anforderung und führe den Handler (der // alle Interceptors enthält) in einer concatMap () aus. Auf diese Weise wird der Handler ausgeführt // innerhalb einer beobachtbaren Kette, wodurch Interceptors bei jedem .__ erneut ausgeführt werden. // Subscription (dies führt auch dazu, dass Wiederholungen den Handler einschließlich Interceptors erneut ausführen).

    var /** @type {?} */ events$ = rxjs_operator_concatMap.concatMap.call(rxjs_observable_of.of(req), function (req) { return _this.handler.handle(req); });

Umgehen:

app.module.ts

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

export let InjectorInstance: Injector;

export class AppModule 
{
  constructor(private injector: Injector) 
  {
    InjectorInstance = this.injector;
  }
}

Ihre statische Klasse/Methode

import {InjectorInstance} from './app.module';

export class SomeNotInjectableService {
  static doSomething() 
  {
  /*  const injector = Injector.create({
      providers: [{provide: HttpClient, deps:[]}]
    });
    const httpClient: HttpClient = injector.get(HttpClient);
*/
    const httpClient =  InjectorInstance.get<HttpClient>(HttpClient);

    httpClient.request(...)...
  }
}

Beispiel für Stackblitz: https://stackblitz.com/edit/angular-li8b37?file=app%2Fapp.component.ts

9
David

Sie können den Injektor auch überspringen, wenn Sie keinen haben. Das bedeutet, dass Sie das "Injizieren" selbst durchführen. Ich empfehle das nicht. Wenn Sie wirklich eine statische Methode verwenden möchten (zugunsten eines ordnungsgemäßen Dienstes), übergeben Sie alle erforderlichen Elemente.

Ich bin nicht sicher, ob dies nicht bereits offensichtlich ist, aber es wird kein HTTP-Interceptor in dieser httpClient-Pipeline fehlen, da es keine Möglichkeit gibt, sie zu lösen.

import { HttpClient, HttpXhrBackend } from '@angular/common/http';

const httpClient = new HttpClient(new HttpXhrBackend({ build: () => new XMLHttpRequest() }));
httpClient.get('test').subscribe(r => console.log(r));

oder mit einem selbst erstellten Injektor (wenn Sie keine ctor args übergeben möchten):

const injector = Injector.create({
    providers: [
        { provide: HttpClient, deps: [HttpHandler] },
        { provide: HttpHandler, useValue: new HttpXhrBackend({ build: () => new XMLHttpRequest }) },
    ],
});
const httpClient: HttpClient = injector.get(HttpClient);
httpClient.get('test').subscribe(r => console.log(r));
9
Andrei Tătar

wenn Sie Interceptors in dieser httpClient-Pipeline verwenden möchten, fügen Sie zwei neu definierte Klassen aus dem Winkelrepo http/src/interceptor.ts und http/src/module.ts hinzu:

class HttpInterceptorHandler implements HttpHandler {
  constructor(private next: HttpHandler, private interceptor: HttpInterceptor) {}

  handle(req: HttpRequest<any>): Observable<HttpEvent<any>> {
      return this.interceptor.intercept(req, this.next);
  }
}
class HttpInterceptingHandler implements HttpHandler {
  private chain: HttpHandler|null = null;
  private httpBackend:HttpHandler;
  constructor(private injector: Injector) {
      this.httpBackend = new HttpXhrBackend({ build: () => new XMLHttpRequest });
  }

  handle(req: HttpRequest<any>): Observable<HttpEvent<any>> {
      if (this.chain === null) {
          const interceptors = this.injector.get(HTTP_INTERCEPTORS, []);
          this.chain = interceptors.reduceRight((next, interceptor) => new HttpInterceptorHandler(next,interceptor),this.httpBackend);
      }
      return this.chain.handle(req);
    }
}

Interceptors müssen ohne @Injectable-Dekorator auskommen:

class HttpIntersept implements HttpInterceptor{
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
      console.log(req.urlWithParams);
      return next.handle(req)
  }
}

Und wie Andrew gesagt hat

const injector = Injector.create({
providers: [
    { provide: HTTP_INTERCEPTORS, useClass: HttpIntersept, multi: true, deps: []},
    { provide: HTTP_INTERCEPTORS, useClass: HttpIntersept2, multi: true, deps: []},
    { provide: HttpHandler, useClass:HttpInterceptingHandler,deps [Injector,HTTP_INTERCEPTORS]},
    { provide: HttpClient, deps: [HttpHandler] }
 ],
});