Angular 如何在静态方法或自定义类中注入HttpClient?

Angular 如何在静态方法或自定义类中注入HttpClient?,angular,typescript,inject,Angular,Typescript,Inject,我想在静态方法或类中使用angularHttpClient(在类中它不能定义为构造函数参数) 我试过这样的方法: export class SomeNotInjectableService { static doSomething() { const injector = Injector.create({ providers: [{provide: HttpClient, deps:[]}] }); const httpClient: HttpClien

我想在静态方法或类中使用angular
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
  }
}

这是在静态服务方法中手动注入客户机的一次尝试。不起作用。我很好奇如何做到这一点,或者如何在普通方法中注入客户机,但在一个不是组件的类中注入客户机。

我不太清楚为什么它不能像您尝试的那样工作(在创建注入器时可能缺少一些东西),但是如果您使用“注入”注入器,它会工作

如果您查看抛出错误的源代码,您会发现它提到了请求的处理程序,在您的示例中它似乎为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); });
解决方法:

应用程序模块.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(...)...
  }
}
从'/app.module'导入{InjectorInstance};
导出类SomeNotInjectableService{
静态剂量测定法()
{
/*const injector=injector.create({
提供者:[{提供:HttpClient,deps:[]}]
});
const-httpClient:httpClient=injector.get(httpClient);
*/
const httpClient=InjectorInstance.get(httpClient);
httpClient.request(…)。。。
}
}
Stackblitz示例:
如果没有喷油器,也可以跳过喷油器。这意味着你要自己“注射”。我不建议这样做。如果你真的想使用一个静态方法(为了一个合适的服务),传递所有需要的东西

我不确定这是否还不明显,但是这个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));
或者使用您自己创建的注入器(如果您不喜欢传递参数):

基于安德鲁的回答。 如果要在此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);
    }
}

将需要的服务/对象作为参数传递会有很大帮助。此外,它还有助于测试和代码的“可读性”。以下解决方案适用于您尝试注入的任何类型的对象。而且,至少,您可以在需要的地方/时候注入它。调用对象负责注入所需的对象

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()*/;
      }
  }

您总是可以避免使用静态方法……不过,问题是如何在普通方法中注入HttpClient,而不是使用构造函数。上述解决方案有效吗?您还需要在静态方法中注入注入器:)我无法找到解决方案。请帮帮我,这是唯一的解决办法吗?如果我想将其作为独立库编写,并避免在任何组件/服务中声明任何内容,该怎么办?这只是一个例子。您的解决方案让我非常满意,但也许还有其他选择。@elzoy抱歉,我不太确定。可能将httpClient实例传递给您的静态方法作为解决方法?这是针对httpClient的。如果我们有相当多的可注入服务要包含在这个定制类中呢。
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()*/;
      }
  }