如何在静态方法或自定义类中注入httpclient



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

这是尝试手动以静态服务方法注入客户端的尝试。行不通。我很好奇如何做到这一点或如何将客户端注入普通方法,而在不是组件的类中。

如果没有一个,也可以跳过注射器。这意味着自己进行"注射"。我不建议这样做。如果您真的想使用静态方法(支持适当的服务(,请传递所有所需的东西。

我不确定这是否尚不明显,但是此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));

我不确定为什么它不按照您的尝试(创建喷油器时缺少的东西(,但是如果您使用'注入'注射器

如果您查看源代码抛出错误,您会看到它会提及该请求的处理程序,这在您的示例中似乎是无效的。当提供httpclient的"传统"方式时,也许是角度记录了一些内部处理程序,但不是这样做的方式

// 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=papp/app.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 Decorator:

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

最新更新