网站搜索

javascript - StaticInjectorError[HttpClent]:不支持的函数/类


我正在尝试手动注入 HttpClientModule,它可能独立于应用程序运行(也许!)。在使用静态注入器之前,我使用的是反射注入器,代码运行良好,但现在反射注入器已经被弃用,我想用静态注入器来更新我的代码。

//appInjector.ts
export class AppInjector {

  private static _instance: AppInjector = new AppInjector();
  private _injector;

  constructor() {
    console.log('app-injector');
    AppInjector._instance = this;
    this._injector = ReflectiveInjector.resolveAndCreate([
        ...[getAnnotations(HttpClientModule)[0].providers],
        MY_HTTP_DEPENDENT_PROVIDERS
        ]);
        
  static getInstance(): AppInjector {
    return AppInjector._instance;
  }

  get(cls: any): any {
    return this._injector.get(cls);
  }
}
//someFile.ts
const translate = AppInjector.getInstance().get(TranslateResource);

参考此帖子了解注解函数。现在,当我尝试使用带静态注入的 Http 客户端时,它出现错误:StaticInjectorError[HttpClent]: 不支持的函数/类

//app module
@NgModule({
  imports: [],
  declarations: [],
  providers: [],
  entryComponents: [App]
})
export class AppModule {
  ngDoBootstrap(app) {
    console.log('bootstrapping');
    app.bootstrap(App);
  }

所以如果我记录,它将记录 app-injector 然后 bootstrapping。

答案#1

StaticInjector 应该是 ReflectiveInjector 的替代,不需要 Reflect API。getAnnotations 是低级的技巧,可能在当前状态下无法与 StaticInjector 一起使用。此外,getAnnotations 天生与 AOT 不兼容。

最好按照框架规定的方式为模块创建注入器,即模块应该被引导。由于没有组件可以引导,因此应指定 ngDoBootstrap 钩子。

默认情况下,引导过程是异步的。如果这不是问题,可以将初始化的 Promise 链接起来以获取模块实例。

一个例子:

@NgModule({
  imports: [BrowserModule, HttpClientModule]
})
export class MyHttpModule {
  static httpClient?: HttpClient;
  httpClient?: HttpClient;

  constructor(private _injector: Injector) {}

  ngDoBootstrap() {
    MyHttpModule.httpClient = this.httpClient = this._injector.get(HttpClient);
  }  
}

platformBrowserDynamic().bootstrapModule(MyHttpModule)
.then((myHttpModule: NgModuleRef<MyHttpModule>) => {
    // HttpClient instance is available here
    const httpClient = myHttpModule.instance.httpClient;
    httpClient.get('/foo', { responseType: 'text'}).subscribe();
})
.catch(err => console.error(err));

这种方法开箱即用地兼容 JIT 和 AOT(这对于在 Angular 之外使用 HttpClient 很有好处,因为这会显著降低占用空间)。

否则可以执行自定义同步引导例程。这是可能的,因为HttpClient不需要异步初始化。

一个例子:

@NgModule({
  imports: [BrowserModule, HttpClientModule]
})
export class MyHttpModule {
  static httpClient?: HttpClient;

  constructor(public _injector: Injector) {
    MyHttpModule.httpClient = this._injector.get(HttpClient);
  }

  ngDoBootstrap() {}  
}

const platform = platformBrowserDynamic();
const compiler = platform.injector.get(CompilerFactory).createCompiler();
const moduleFactory = compiler.compileModuleSync(MyHttpModule);

platform.bootstrapModuleFactory(moduleFactory)
.catch(err => console.error(err));

const httpClient = MyHttpModule.httpClient;
httpClient.get('/foo').subscribe();

这将在 JIT 中工作,但在上面的代码中,Angular CLI 无法高效处理 AOT。该代码涉及编译器,而在 AOT 编译模式下不需要编译器(这正是它的目的)。为了使用 AOT,应该使用 ngc 编译器进行编译,并创建一个使用模块工厂的单独入口点。引导过程变得更简单,因为它不涉及编译器,比如这样:

...
import { platformBrowser } from '@angular/platform-browser-dynamic';
import { AppModuleNgFactory } from '<path to aot>/src/app/my-http-module.ngfactory';

const platform = platformBrowser();
platform.bootstrapModuleFactory(AppModuleNgFactory)
.catch(err => console.error(err));

const httpClient = MyHttpModule.httpClient;
httpClient.get('/foo').subscribe();