【问题标题】:Inject Http manually in Angular 4在 Angular 4 中手动注入 Http
【发布时间】:2017-12-25 12:25:11
【问题描述】:

我想手动引导一个 Angular 4 应用程序(使用 CLI 创建)。 在main.ts 我正在这样做:

const injector = ReflectiveInjector.resolveAndCreate([
  Http,
  BrowserXhr,
  {provide: RequestOptions, useClass: BaseRequestOptions},
  {provide: ResponseOptions, useClass: BaseResponseOptions},
  {provide: ConnectionBackend, useClass: XHRBackend},
  {provide: XSRFStrategy, useFactory: () => new CookieXSRFStrategy()},
]);
const http = injector.get(Http);

http.get('assets/configs/configuration.json')
  .map((res: Response) => {
    return res.json();
  }).subscribe((config: Configuration) => {
  configuration = config;
  console.log(JSON.stringify(configuration));
  platformBrowserDynamic().bootstrapModule(AppModule);
});

我似乎得到了一个有效的 Http 实例,但是当我使用它时 (http.get) 我得到了这个错误:

Uncaught TypeError: Cannot read property 'getCookie' of null
    at CookieXSRFStrategy.webpackJsonp.../../../http/@angular/http.es5.js.CookieXSRFStrategy.configureRequest (vendor.bundle.js:141626)

我的 http 对象如下所示:

【问题讨论】:

标签: angular


【解决方案1】:

您可以在 Angular 开始使用 ReflectiveInjector 之前使用 HttpClient 服务,如下所示:

import { ReflectiveInjector } from '@angular/core';
import { HttpClient, HttpClientModule } from '@angular/common/http';
const injector = ReflectiveInjector.resolveAndCreate(getAnnotations(HttpClientModule)[0].providers);

const http = injector.get(HttpClient);
http.get('/posts/1').subscribe((r) => {
  ConfigurationService.configuration = <Configuration>JSON.parse(config);
  platformBrowserDynamic().bootstrapModule(AppModule);
});

这一行:

getAnnotations(HttpClientModule).providers

引用在HttpClientModule 上注册的所有提供程序,因此您不必手动指定它们。 This answer 详细解释了 getAnnotations 函数。

我展示的方法“有点”类似于您将HttpClientModule 导入AppModule 时所做的:

@NgModule({
    imports: [HttpClientModule, ...],
})
export class AppModule {}

详情请见this plunker

【讨论】:

  • 谢谢,马克西姆斯。这看起来像是下一个版本可能会更改的代码。我想我现在会坚持我的解决方案。但是,您的提交回答了我的问题,我会将其标记为已接受(虽然我还没有尝试过)。
  • 不客气,如果有帮助,您可以接受或支持我的回答。你也可以展示你如何使用ConfigurationService
  • @hholtij,谢谢。这里只有两个部分可能会受到更新 httpFactory_createDefaultCookieXSRFStrategy 函数的影响。理论上可以尝试找到不使用它们的方法,至少_createDefaultCookieXSRFStrategy。其他所有内容都是公开支持的,如果它发生变化,那么您还必须更新在 Angular 应用程序中使用 http 的所有代码。另外我仍然对ConfigurationService 感兴趣。然后你会在某处使用它作为提供者吗?
  • ConfigurationService 曾经是读取配置文件的服务。我们现在使用 NSwagStudio 工具从 swagger 定义中自动生成 api 服务。它工作得很好,但需要在引导应用程序之前读取配置文件,因为它包含 api url。现在,ConfigurationService 基本上只是一个具有静态属性的类。也可能会改变这一点。
  • 我刚刚尝试了您的解决方案,Maximus。它对我不起作用。我得到同样的错误: Uncaught TypeError: Cannot read property 'getCookie' of null at CookieXSRFStrategy.webpackJsonp.../../../http/@angular/http.es5.js.CookieXSRFStrategy.configureRequest
【解决方案2】:

作为另一种方法,您可以使用本机浏览器fetch api。所以你不必处理 angular http 等

我就是这样做的:

fetch(configUrl, { method: 'get' })
.then((response) => {
  response.json()
    .then((data: any) => {
      if (environment.production) {
        enableProdMode();
      };
      platformBrowserDynamic([{ provide: AppSettings, useValue: new AppSettings(data.config) }]).bootstrapModule(AppModule);
    });
});

但请记住,fetchold browsers 中并没有得到太多的爱,所以如果你想支持,你需要用whatwg-fetchnpm install whatwg-fetch --save 然后在polyfills.ts 中添加import 'whatwg-fetch'旧浏览器。

更新: 是的,您可以使用XMLHttpRequest,但您将获得与fetch 相同的浏览器支持,只是XMLHttpRequest 的现代替代品。

【讨论】:

  • 但是他用 Injector 创建它们,他不依赖框架来提供它们
  • @Maximus 啊,我不知道,感谢告知,但至少可以看到一个缺点 - 它就像代码的 3 倍;)
  • 是的,当然,因为Angular 提供的httpfetch 做得更多:)
  • 还应该指出,我认为这种方法对未来更安全
【解决方案3】:

可能原来的答案以前有效,但在 Angular 5 中我无法使用它,函数 getAnnotations 没有定义。然而,这对我有用:

import { ReflectiveInjector } from '@angular/core';
import {
  HttpClient,
  XhrFactory,
  HttpHandler,
  HttpXhrBackend,
  HttpBackend
} from '@angular/common/http';

// https://github.com/angular/angular/blob/master/packages/common/http/src/xhr.ts#L45
export class BrowserXhr implements XhrFactory {
  build(): any { return <any>(new XMLHttpRequest()); }
}

const injector = ReflectiveInjector.resolveAndCreate([
  HttpClient,
  HttpXhrBackend,
  { provide: HttpBackend, useExisting: HttpXhrBackend },
  { provide: HttpHandler, useExisting: HttpBackend },
  { provide: XhrFactory, useClass: BrowserXhr},
]);

const http: HttpClient = injector.get(HttpClient);

http.get('/url').subscribe((response) => {
  console.log(response);
});

【讨论】:

    【解决方案4】:

    谢谢,昆切维奇。我想出了这个解决方案,效果很好:

    function httpGetAsync(theUrl, callback) {
      const xmlHttp = new XMLHttpRequest();
    
      xmlHttp.onreadystatechange = function() {
        if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
          callback(xmlHttp.responseText);
        }
      }
    
      xmlHttp.open('GET', theUrl, true); // true for asynchronous
      xmlHttp.send(null);
    }
    
    httpGetAsync('assets/configs/configuration.json', (config: string) => {
      ConfigurationService.configuration = <Configuration>JSON.parse(config);
      platformBrowserDynamic().bootstrapModule(AppModule);
    });
    

    【讨论】:

      猜你喜欢
      • 2018-06-04
      • 2018-05-17
      • 1970-01-01
      • 2016-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-31
      相关资源
      最近更新 更多