typescript 如何在静态方法或自定义类中注入 HttpClient?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/49507928/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to inject HttpClient in static method or custom class?
提问by elzoy
I'd like to use angular HttpClient
in static method or class (in class it can't be defined as constructor parameter).
我想HttpClient
在静态方法或类中使用 angular (在类中它不能定义为构造函数参数)。
I tried something like:
我试过类似的东西:
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
}
}
this is a try of injecting manually the client in static service method. Doesn't work. I'm curious how to do this or how to inject the client in normal method but in a class which isn't a component.
这是在静态服务方法中手动注入客户端的尝试。不起作用。我很好奇如何做到这一点或如何以普通方法但在不是组件的类中注入客户端。
回答by David
I'm not exactly sure why it does not work the way you tried (probably something missing when you create the injector), but it works if you use an 'injected' injector
我不确定为什么它不能像您尝试的那样工作(可能在您创建注射器时缺少某些东西),但是如果您使用“注入”注射器它会起作用
If you look at the source code throwing the error you see that it mentions handlers for the request, which seems to be null in your example. Maybe angular registers some internal handlers when the HttpClient is provided the 'traditional' way, but not the way you do it
如果您查看抛出错误的源代码,您会发现它提到了请求的处理程序,在您的示例中似乎为 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); });
Work around:
解决:
app.module.ts
app.module.ts
import {Injector} from '@angular/core';
export let InjectorInstance: Injector;
export class AppModule
{
constructor(private injector: Injector)
{
InjectorInstance = this.injector;
}
}
Your static class/method
你的静态类/方法
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(...)...
}
}
Example on Stackblitz: https://stackblitz.com/edit/angular-li8b37?file=app%2Fapp.component.ts
Stackblitz 示例:https://stackblitz.com/edit/angular-li8b37 ?file =app%2Fapp.component.ts
回答by Andrei T?tar
You can also skip the injector if you don't have one. That means doing the 'injecting' yourself. I don't recommend doing this. If you really want to use a static method (in favor of a proper service), pass all the needed stuff.
如果您没有注射器,您也可以跳过注射器。这意味着自己进行“注射”。我不建议这样做。如果您真的想使用静态方法(支持适当的服务),请传递所有需要的东西。
I'm not sure if this isn't already obvious but any HTTP interceptor will be missing from this httpClient pipeline, since there's no way of resolving them.
我不确定这是否还不是很明显,但是此 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));
or using your own created injector (if you don't like passing ctor args):
或使用您自己创建的注入器(如果您不喜欢传递 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));
回答by Дмитрий Гаганов
base on Andrew answer. If you want to use interceptors in this this httpClient pipeline, add two redefined classes from angular repo http/src/interceptor.ts and http/src/module.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);
}
}
Interceptors need without @Injectable decorator:
拦截器不需要@Injectable 装饰器:
class HttpIntersept implements HttpInterceptor{
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log(req.urlWithParams);
return next.handle(req)
}
}
And like Andrew was say
就像安德鲁说的
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] }
],
});
回答by Bellash
Passing the need service/object as a parameter helps a lot. In addition, it helps testing and code "readability". This following solution works with any type of object you are trying to inject. And, at least, you inject it where/when needed. The calling object is responsible for injecting the needed object.
将需要的服务/对象作为参数传递有很大帮助。此外,它有助于测试和编码“可读性”。以下解决方案适用于您尝试注入的任何类型的对象。而且,至少,您可以在需要的地方/时间注入它。调用对象负责注入所需的对象。
export class SomeNotInjectableService {
static doSomething(injected: any) {
httpClient = injected as HttpClient;
if(httpClient) {
httpClient.get(...);
}
}
}
then in your calling component or service, use it like this
然后在您的调用组件或服务中,像这样使用它
...
export class MyService/*or MyComponent*/{
constructor(private http: HttpClient){}
doTheThing(){
SomeNotInjectableService.doSomething(this.http)/*...subscribe()*/;
}
}