Angular 2/5。使用 HttpClient 的服务出错并且不起作用

Angular 2/5. Service with HttpClient makes mistake and doesn't works

我正在尝试提供从远程服务器获取(尝试获取)XML 文件的服务。我没有足够的经验自己找错误。 app.component.ts的相关代码:

import { Component, OnInit, AfterViewInit, ElementRef, ViewChild, Renderer2 } from '@angular/core';
import { CanvasSettings } from './canvas-settings';
import { Rate } from './rate';
import { RateService } from './rates.service';
import { CBRRateService } from './cbrrates.service';
import { DatePoints, Year, Month, Day, Monthes, ofMonth } from './dates';
import { HttpClient, HttpHandler, HttpClientModule } from '@angular/common/http';

@Component({ // line 9, there is an error
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
    providers: [ RateService, CBRRateService, HttpClient, HttpHandler, HttpClientModule ]
})

export class AppComponent implements OnInit, AfterViewInit {

    @ViewChild("helper") helper: ElementRef;

    //...
    rates: Rate[];
    cbrrates: any;
    //...

    constructor(private _rateService: RateService, private _rateCBRService: CBRRateService) {}

    ngOnInit() {

        //...

    }

    getCBRRates():void { // Uses http. Doesn't work.

        this._rateCBRService.getCBRRates().subscribe(cbrrates => {this.cbrrates = cbrrates});

    }
    getRates():void { // Doesn't use http, works fine

        this._rateService.getRates().subscribe(rates => this.rates = rates);

    }

    //...

}

以及cbrrates.service.ts的代码清单:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient, HttpHandler, HttpClientModule, HttpHeaders } from '@angular/common/http';
import { of } from 'rxjs/observable/of'; // It used in earlier version, now it useless

const httpOptions = {
    headers: new HttpHeaders({ 'Content-Type': 'plain/text' }) // I've found no way to get XML, so 'plain/text'. Everywhere JSON.
};

@Injectable()
export class CBRRateService {

    targetURL: string = "http://www.cbr.ru/scripts/XML_dynamic.asp?date_req1=01/01/2016&date_req2=02/02/2018&VAL_NM_RQ=R01235";

    constructor(private http: HttpClient){}

    getCBRRates(): Observable<any> {
        return (this.http.get(this.targetURL, {responseType: 'text'}));
    }

}

bash 控制台出错:

 ERROR in src/app/app.component.ts(9,12): error TS2345:
 Argument of type '{ selector: string; templateUrl: string;
 styleUrls: string[]; providers: (typeof HttpHandler | ty...' is not
 assignable to parameter of type 'Component'.

   Types of property 'providers' are incompatible.

     Type '(typeof HttpHandler | typeof HttpClient | typeof HttpClientModule
 | typeof CBRRateService)[]' is not assignable to type 'Provider[]'.

       Type 'typeof HttpHandler | typeof HttpClient | typeof HttpClientModule
 | typeof CBRRateService' is not assignable to type 'Provider'.

         Type 'typeof HttpHandler' is not assignable to type 'Provider'.

           Type 'typeof HttpHandler' is not assignable to type 'ClassProvider'.

             Property 'provide' is missing in type 'typeof HttpHandler'.

浏览器控制台错误:

Failed to load resource: the server responded with a status of 404 (Not Found)

共2题:

  1. 如何修复服务 CBRRateService 并使其正常工作?

  2. 是否存在通过从远程服务器获取数据的服务获取和解析 XML-数据的方法?

无法发表评论,所以我发布了一个答案: 将 HttpModule 导入到应用程序模块中,并将其注入到构造函数中。

请注意新的 HttpClientModule 已在版本 4.3 中引入并在包 @angular/common/http 中可用,并且是前者 HttpModule 的完整重新实现。新的 HttpClient 服务包含在 HttpClientModule 中,可用于在您的应用程序中发起 HTTP 请求和处理响应。 您可能使用了错误的版本!

更新:因为你有 angular providers array tour 中的模块扰乱了依赖注入

providers: [
    CBRRateService, OtherService, // don't bring angular modules and classes here
]

@MikhailFilchushkin,当你写 this.http.get(this.targetURL, {responseType: 'text'}) 时,你在回复中写了一个 "string"。因此,您必须将此字符串转换为一个对象。你可以这样做

getCBRRates(): Observable<any> {
    return this.httpClient.get(this.targetURL, { responseType: 'text' })
      .map((response: string) => { //response is a string
        let result: any[] = [];
        let records = response.split('<Record'); //make a array of string
        let index = 0;
        records.forEach(r => {
          let date = r.split('Date=');
          let id = r.split('Id=');
          let nominal = r.split('<Nominal>');
          let value = r.split('<Value>');
          if (index > 0) { //the first is the header of the xml
            result.push({
              date: date[1].substr(1,10), //date[0] is the text before "Date"
              id: id[1].substr(1,6), //idem id
              nominal: nominal[1].substring(0,nominal[1].indexOf('<')),
              value: value[1].substring(0,value[1].indexOf('<')),
            })
          }
          index++;

        });
        return result;
      });
  }