Angular9 請求數(shù)據(jù)

2020-07-06 14:19 更新

使用 HTTPClient.get() 方法從服務(wù)器獲取數(shù)據(jù)。該異步方法會發(fā)送一個 HTTP 請求,并返回一個 Observable,它會在收到響應(yīng)時發(fā)出所請求到的數(shù)據(jù)。返回的類型取決于你調(diào)用時傳入的 observeresponseType 參數(shù)。

get() 方法有兩個參數(shù)。要獲取的端點 URL,以及一個可以用來配置請求的選項對象。

options: {
    headers?: HttpHeaders | {[header: string]: string | string[]},
    observe?: 'body' | 'events' | 'response',
    params?: HttpParams|{[param: string]: string | string[]},
    reportProgress?: boolean,
    responseType?: 'arraybuffer'|'blob'|'json'|'text',
    withCredentials?: boolean,
  }

這些重要的選項包括 observeresponseType 屬性。

  • observe 選項用于指定要返回的響應(yīng)內(nèi)容。

  • responseType 選項指定返回數(shù)據(jù)的格式。

你可以使用 options 對象來配置傳出請求的各個方面。例如,在 Adding headers 中,該服務(wù)使用 headers 選項屬性設(shè)置默認頭。

使用 params 屬性可以配置帶 HTTP URL 參數(shù)的請求, reportProgress 選項可以在傳輸大量數(shù)據(jù)時監(jiān)聽進度事件。

應(yīng)用經(jīng)常會從服務(wù)器請求 JSON 數(shù)據(jù)。在 ConfigService 例子中,該應(yīng)用需要服務(wù)器 "config.json" 上的一個配置文件來指定資源的 URL。

Path:"assets/config.json" 。

{
  "heroesUrl": "api/heroes",
  "textfile": "assets/textfile.txt"
}

要獲取這類數(shù)據(jù),get() 調(diào)用需要以下幾個選項: {observe: 'body', responseType: 'json'}。這些是這些選項的默認值,所以下面的例子不會傳遞 options 對象。后面幾節(jié)展示了一些額外的選項。

這個例子符合通過定義一個可重用的可注入服務(wù)來執(zhí)行數(shù)據(jù)處理功能來創(chuàng)建可伸縮解決方案的最佳實踐。除了提取數(shù)據(jù)外,該服務(wù)還可以對數(shù)據(jù)進行后處理,添加錯誤處理,并添加重試邏輯。

ConfigService 使用 HttpClient.get() 方法獲取這個文件。

Path:"app/config/config.service.ts (getConfig v.1)" 。

configUrl = 'assets/config.json';


getConfig() {
  return this.http.get(this.configUrl);
}

ConfigComponent 注入了 ConfigService 并調(diào)用了 getConfig 服務(wù)方法。

由于該服務(wù)方法返回了一個 Observable 配置數(shù)據(jù),該組件會訂閱該方法的返回值。訂閱回調(diào)只會對后處理進行最少量的處理。它會把數(shù)據(jù)字段復制到組件的 config 對象中,該對象在組件模板中是數(shù)據(jù)綁定的,用于顯示。

Path:"app/config/config.component.ts (showConfig v.1)" 。

showConfig() {
  this.configService.getConfig()
    .subscribe((data: Config) => this.config = {
        heroesUrl: data['heroesUrl'],
        textfile:  data['textfile']
    });
}

請求輸入一個類型的響應(yīng)

你可以構(gòu)造自己的 HttpClient 請求來聲明響應(yīng)對象的類型,以便讓輸出更容易、更明確。所指定的響應(yīng)類型會在編譯時充當類型斷言。

注:

  • 指定響應(yīng)類型是在向 TypeScript 聲明,它應(yīng)該把你的響應(yīng)對象當做給定類型來使用。這是一種構(gòu)建期檢查,它并不能保證服務(wù)器會實際給出這種類型的響應(yīng)對象。該服務(wù)器需要自己確保返回服務(wù)器 API 中指定的類型。

要指定響應(yīng)對象類型,首先要定義一個具有必需屬性的接口。這里要使用接口而不是類,因為響應(yīng)對象是普通對象,無法自動轉(zhuǎn)換成類的實例。

export interface Config {
  heroesUrl: string;
  textfile: string;
}

接下來,在服務(wù)器中把該接口指定為 HttpClient.get() 調(diào)用的類型參數(shù)。

Path:"app/config/config.service.ts (getConfig v.2)" 。

getConfig() {
  // now returns an Observable of Config
  return this.http.get<Config>(this.configUrl);
}

當把接口作為類型參數(shù)傳給 HttpClient.get() 方法時,你可以使用RxJS map 操作符來根據(jù) UI 的需求轉(zhuǎn)換響應(yīng)數(shù)據(jù)。然后,把轉(zhuǎn)換后的數(shù)據(jù)傳給異步管道。

修改后的組件方法,其回調(diào)函數(shù)中獲取一個帶類型的對象,它易于使用,且消費起來更安全:

Path:"app/config/config.component.ts (showConfig v.2)" 。

config: Config;


showConfig() {
  this.configService.getConfig()
    // clone the data object, using its known Config shape
    .subscribe((data: Config) => this.config = { ...data });
}

要訪問接口中定義的屬性,必須將從 JSON 獲得的普通對象顯式轉(zhuǎn)換為所需的響應(yīng)類型。例如,以下 subscribe 回調(diào)會將 data 作為對象接收,然后進行類型轉(zhuǎn)換以訪問屬性。

.subscribe(data => this.config = {
  heroesUrl: (data as any).heroesUrl,
  textfile:  (data as any).textfile,
});

OBSERVERESPONSE 的類型是字符串的聯(lián)合類型,而不是普通的字符串。

options: {
    ...
    observe?: 'body' | 'events' | 'response',
    ...
    responseType?: 'arraybuffer'|'blob'|'json'|'text',
    ...
  }

這會引起混亂。例如:

// this works
client.get('/foo', {responseType: 'text'})


// but this does NOT work
const options = {
  responseType: 'text',
};
client.get('/foo', options)

在第二種情況下,TypeScript 會把 options 的類型推斷為 {responseType: string}。該類型的 HttpClient.get 太寬泛,無法傳遞給 HttpClient.get,它希望 responseType 的類型是特定的字符串之一。而 HttpClient 就是以這種方式顯式輸入的,因此編譯器可以根據(jù)你提供的選項報告正確的返回類型。

使用 as const,可以讓 TypeScript 知道你并不是真的要使用字面字符串類型:

const options = {
  responseType: 'text' as const,
};
client.get('/foo', options);

讀取完整的響應(yīng)體

在前面的例子中,對 HttpClient.get() 的調(diào)用沒有指定任何選項。默認情況下,它返回了響應(yīng)體中包含的 JSON 數(shù)據(jù)。

你可能還需要關(guān)于這次對話的更多信息。比如,有時候服務(wù)器會返回一個特殊的響應(yīng)頭或狀態(tài)碼,來指出某些在應(yīng)用的工作流程中很重要的條件。

可以用 get() 方法的 observe 選項來告訴 HttpClient,你想要完整的響應(yīng)對象:

getConfigResponse(): Observable<HttpResponse<Config>> {
  return this.http.get<Config>(
    this.configUrl, { observe: 'response' });
}

現(xiàn)在,HttpClient.get() 會返回一個 HttpResponse 類型的 Observable,而不只是 JSON 數(shù)據(jù)。

該組件的 showConfigResponse() 方法會像顯示配置數(shù)據(jù)一樣顯示響應(yīng)頭:

Path:"app/config/config.component.ts (showConfigResponse)" 。

showConfigResponse() {
  this.configService.getConfigResponse()
    // resp is of type `HttpResponse<Config>`
    .subscribe(resp => {
      // display its headers
      const keys = resp.headers.keys();
      this.headers = keys.map(key =>
        `${key}: ${resp.headers.get(key)}`);


      // access the body directly, which is typed as `Config`.
      this.config = { ... resp.body };
    });
}

注:

  • 該響應(yīng)對象具有一個帶有正確類型的 body 屬性。

發(fā)起 JSONP 請求

當服務(wù)器不支持 CORS 協(xié)議時,應(yīng)用程序可以使用 HttpClient 跨域發(fā)出 JSONP 請求。

Angular 的 JSONP 請求會返回一個 Observable。 遵循訂閱可觀察對象變量的模式,并在使用async 管道管理結(jié)果之前,使用 RxJS map 操作符轉(zhuǎn)換響應(yīng)。

在 Angular 中,通過在 NgModuleimports 中包含 HttpClientJsonpModule 來使用 JSONP。在以下示例中,searchHeroes() 方法使用 JSONP 請求來查詢名稱包含搜索詞的英雄。

/* GET heroes whose name contains search term */
searchHeroes(term: string): Observable {
  term = term.trim();


  let heroesURL = `${this.heroesURL}?${term}`;
  return this.http.jsonp(heroesUrl, 'callback').pipe(
      catchError(this.handleError('searchHeroes', [])) // then handle the error
    );
};

該請求將 heroesURL 作為第一個參數(shù),并將回調(diào)函數(shù)名稱作為第二個參數(shù)。響應(yīng)被包裝在回調(diào)函數(shù)中,該函數(shù)接受 JSONP 方法返回的可觀察對象,并將它們通過管道傳給錯誤處理程序。

請求非 JSON 數(shù)據(jù)

不是所有的 API 都會返回 JSON 數(shù)據(jù)。在下面這個例子中,DownloaderService 中的方法會從服務(wù)器讀取文本文件, 并把文件的內(nèi)容記錄下來,然后把這些內(nèi)容使用 Observable<string> 的形式返回給調(diào)用者。

Path:"app/downloader/downloader.service.ts (getTextFile)" 。

getTextFile(filename: string) {
  // The Observable returned by get() is of type Observable<string>
  // because a text response was specified.
  // There's no need to pass a <string> type parameter to get().
  return this.http.get(filename, {responseType: 'text'})
    .pipe(
      tap( // Log the result or error
        data => this.log(filename, data),
        error => this.logError(filename, error)
      )
    );
}

這里的 HttpClient.get() 返回字符串而不是默認的 JSON 對象,因為它的 responseType 選項是 'text'。

RxJS 的 tap 操作符(如“竊聽”中所述)使代碼可以檢查通過可觀察對象的成功值和錯誤值,而不會干擾它們。

DownloaderComponent 中的 download() 方法通過訂閱這個服務(wù)中的方法來發(fā)起一次請求。

Path:"app/downloader/downloader.component.ts (download)" 。

download() {
  this.downloaderService.getTextFile('assets/textfile.txt')
    .subscribe(results => this.contents = results);
}
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號