Fetch() 簡介

Matt Gaunt

fetch() 可讓您發出類似 XMLHttpRequest (XHR) 的網路要求。主要差異在於 Fetch API 使用 Promise,後者提供更簡單的 API,可協助您避免使用 XMLHttpRequest API 中的複雜回呼。

瀏覽器支援

  • Chrome:42。
  • Edge:14。
  • Firefox:39。
  • Safari:10.1。

資料來源

如果您沒用過 Promise 請先參閱 JavaScript Promise 簡介

基本擷取要求

以下是使用 XMLHttpRequestfetch 實作的範例。我們想要求存取網址、取得回應以及剖析 匯出為 JSON

XMLHttpRequest

XMLHttpRequest 需要兩個事件監聽器來處理成功和錯誤案例,以及對 open()send() 的呼叫。MDN 文件範例

function reqListener () {
  const data = JSON.parse(this.responseText);
  console.log(data);
}

function reqError (err) {
  console.log('Fetch Error :-S', err);
}

const oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();

擷取

我們的擷取要求如下所示:

fetch('./api/some.json')
  .then(response => {
    if (response.status !== 200) {
      console.log(`Looks like there was a problem. Status Code: ${response.status}`);

      return;
    }

    // Examine the text in the response
    response.json().then(function(data) {
      console.log(data);
    });
  })
  .catch(err => {
    console.log('Fetch Error :-S', err);
  });

fetch() 要求只需要一個呼叫就能執行與 XHR 相同的工作 範例。為了處理回應,我們會先檢查回應狀態是否為 200,然後將回應解析為 JSON。fetch() 要求的回應是 Stream 物件,也就是說, 我們呼叫了 json() 方法,會傳回 Promise。 串流會以非同步方式發生。

回應中繼資料

上一個範例顯示了 Response 物件的狀態,以及如何將回應解析為 JSON。以下說明如何處理您可能要存取的其他中繼資料,例如標頭:

fetch('users.json').then(response => {
  console.log(response.headers.get('Content-Type'));
  console.log(response.headers.get('Date'));

  console.log(response.status);
  console.log(response.statusText);
  console.log(response.type);
  console.log(response.url);
});

回應類型

當我們提出擷取要求時,回應會獲得 response.typebasic」, 「cors」或 「opaque」。 這些types會顯示資源的來源,您可以使用這些資源 判斷如何處理回應物件

當瀏覽器要求相同來源的資源時,回應會具有 basic 類型,並限制您可以從回應中查看的內容。

如果對另一個來源的資源發出要求,且該來源會傳回 COR 標頭,則類型為 corscors 回應類似於 basic 回應,但會限制 可查看「Cache-Control」、「Content-Language」、「Content-Type」、「Expires」和 Last-ModifiedPragma

opaque 回應來自不同的來源,該來源不會傳回 CORS 標頭。由於回應內容不透明,我們無法讀取傳回的資料或查看要求狀態,也就是說,您無法檢查要求是否成功。

您可以為擷取要求定義模式,讓系統只解析特定要求類型。您可以設定的模式如下:

  • same-origin 只會成功處理同一個來源的素材資源要求,並拒絕所有其他要求。
  • cors 允許要求相同來源及其他來源的資產 會傳回適當的 COR 標頭。
  • cors-with-forced-preflight 會執行預檢 查看 再提出要求
  • no-cors 的用途是向其他沒有 CORS 的來源發出要求 標頭並產生 opaque 回應,但如 所述,這並非 都可以使用這項工具

如要定義模式,請在 fetch 要求中新增選項物件做為第二個參數,並在該物件中定義模式:

fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
  .then(response => response.text())
  .then(text => {
    console.log('Request successful', text);
  })
  .catch(error => {
    log('Request failed', error)
  });

承諾鏈結

實現承諾的一大特色是能夠鏈結在一起。對於 fetch(),這可讓您在擷取要求之間共用邏輯。

如果您使用的是 JSON API,則需要檢查狀態,並剖析每個回應的 JSON。您可以透過在傳回承諾的個別函式中定義狀態和 JSON 剖析,並使用擷取要求只處理最終資料和錯誤情況,藉此簡化程式碼。

function status (response) {
  if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
  } else {
    return Promise.reject(new Error(response.statusText))
  }
}

function json (response) {
  return response.json()
}

fetch('users.json')
  .then(status)
  .then(json)
  .then(data => {
    console.log('Request succeeded with JSON response', data);
  }).catch(error => {
    console.log('Request failed', error);
  });

這個範例定義了 status 函式,用於檢查 response.status,並傳回已解析的 Promise 做為 Promise.resolve(),或傳回已拒絕的 Promise 做為 Promise.reject()。這是 fetch() 鏈結中呼叫的第一個方法。

如果 Promise 已解析,指令碼會呼叫 json() 方法, 從 response.json() 呼叫傳回第二個 Promise,並 物件,當中含有剖析 JSON 檔案。如果剖析失敗,承諾會遭到拒絕,並執行 catch 陳述式。

這個結構可讓您在所有擷取要求中共用邏輯, 維護、讀取及測試程式碼變得更簡單

POST 要求

有時候,網頁應用程式需要使用 POST 方法呼叫 API,並加入一些 參數中。如要這麼做,請在 fetch() 選項中設定 methodbody 參數:

fetch(url, {
    method: 'post',
    headers: {
      "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
    },
    body: 'foo=bar&lorem=ipsum'
  })
  .then(json)
  .then(data => {
    console.log('Request succeeded with JSON response', data);
  })
  .catch(error => {
    console.log('Request failed', error);
  });

透過擷取要求傳送憑證

如要提出含有憑證 (例如 Cookie) 的擷取要求,請將要求的 credentials 值設為 "include"

fetch(url, {
  credentials: 'include'
})