簡體   English   中英

如何在靜態方法或自定義類中注入 HttpClient?

[英]How to inject HttpClient in static method or custom class?

我想在靜態方法或類中使用HttpClient (在類中它不能定義為構造函數參數)。

我試過類似的東西:

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

這是在靜態服務方法中手動注入客戶端的嘗試。 不起作用。 我很好奇如何做到這一點或如何以普通方法但在不是組件的類中注入客戶端。

如果您沒有注射器,您也可以跳過注射器。 這意味着自己進行“注射”。 我不建議這樣做。 如果您真的想使用靜態方法(支持適當的服務),請傳遞所有需要的東西。

我不確定這是否還不是很明顯,但是此 httpClient 管道中將缺少任何 HTTP 攔截器,因為無法解析它們。

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

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

或使用您自己創建的注入器(如果您不喜歡傳遞 ctor args):

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

我不確定為什么它不能像您嘗試的那樣工作(可能在您創建注入器時缺少某些東西),但是如果您使用“注入”注入器,它會起作用

如果您查看拋出錯誤的源代碼,您會看到它提到了請求的處理程序,在您的示例中似乎為 null。 當 HttpClient 以“傳統”方式提供時,Angular 可能會注冊一些內部處理程序,但不是您提供的方式

// Start with an Observable.of() the initial request, and run the handler (which
// includes all interceptors) inside a concatMap(). This way, the handler runs
// inside an Observable chain, which causes interceptors to be re-run on every
// subscription (this also makes retries re-run the handler, including interceptors).

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

解決:

app.module.ts

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

export let InjectorInstance: Injector;

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

你的靜態類/方法

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(...)...
  }
}

Stackblitz 示例: https ://stackblitz.com/edit/angular-li8b37 ? file = app%2Fapp.component.ts

基於安德魯的回答。 如果你想在這個 httpClient 管道中使用攔截器,從 angular repo http/src/interceptor.ts 和 http/src/module.ts 添加兩個重新定義的類:

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

攔截器不需要@Injectable 裝飾器:

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

就像安德魯說的

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

將需要的服務/對象作為參數傳遞有很大幫助。 此外,它有助於測試和編碼“可讀性”。 以下解決方案適用於您嘗試注入的任何類型的對象。 而且,至少,您可以在需要的地方/時間注入它。 調用對象負責注入所需的對象。

export class SomeNotInjectableService {
  static doSomething(injected: any) {
    httpClient = injected as HttpClient;
    if(httpClient) {
       httpClient.get(...);
     }
  }
}

然后在您的調用組件或服務中,像這樣使用它

  ...
  export class MyService/*or MyComponent*/{
      constructor(private http: HttpClient){}
      doTheThing(){
          SomeNotInjectableService.doSomething(this.http)/*...subscribe()*/;
      }
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM