Angular9 請求數據

2020-07-06 14:19 更新

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

get() 方法有兩個參數。要獲取的端點 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 選項用于指定要返回的響應內容。

  • responseType 選項指定返回數據的格式。

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

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

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

Path:"assets/config.json" 。

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

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

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

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 并調用了 getConfig 服務方法。

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

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

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

請求輸入一個類型的響應

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

注:

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

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

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

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

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

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

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

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

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 獲得的普通對象顯式轉換為所需的響應類型。例如,以下 subscribe 回調會將 data 作為對象接收,然后進行類型轉換以訪問屬性。

.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 就是以這種方式顯式輸入的,因此編譯器可以根據你提供的選項報告正確的返回類型。

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

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

讀取完整的響應體

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

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

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

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

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

該組件的 showConfigResponse() 方法會像顯示配置數據一樣顯示響應頭:

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 };
    });
}

注:

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

發(fā)起 JSONP 請求

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

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

在 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 作為第一個參數,并將回調函數名稱作為第二個參數。響應被包裝在回調函數中,該函數接受 JSONP 方法返回的可觀察對象,并將它們通過管道傳給錯誤處理程序。

請求非 JSON 數據

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

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() 方法通過訂閱這個服務中的方法來發(fā)起一次請求。

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

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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號