Fetch() 簡介

Matt Gaunt

fetch() 可讓您發出類似 XMLHttpRequest (XHR) 的網路要求。主要差別在於 Fetch API 使用 Promise,而 Promise 具有更簡易的 API,有助於避免 XMLHttpRequest API 中的複雜回呼。

瀏覽器支援

  • 42
  • 14
  • 39
  • 10.1

來源

如果您從未使用過 Promise,請參閱 JavaScript Promise 簡介

基本擷取要求

以下是透過 XMLHttpRequest 搭配 fetch 實作的範例。我們想要要求網址、取得回應,並將網址剖析為 JSON。

XMLHttpRequest

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

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

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

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

擷取

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

fetch('./api/some.json')
  .then(
  function(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(function(err) {
    console.log('Fetch Error :-S', err);
  });

fetch() 要求只需要一次呼叫即可執行與 XHR 範例相同的工作。如要處理回應,我們會先檢查回應狀態是否為 200,然後再將回應剖析為 JSON。fetch() 要求的回應是 Stream 物件,這表示在呼叫 json() 方法後,會傳回 Promise。串流會以非同步方式進行。

回應中繼資料

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

fetch('users.json').then(function(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);
});

回應類型

提出擷取要求時,系統會在回應中提供「basic」、「cors」或「opaque」的 response.type。這些 types 會顯示資源的來源,方便您用來決定回應物件的方式。

當瀏覽器要求來自相同來源的資源時,回應會具有 basic 類型,並限制回應中可檢視的內容。

如果對另一個來源的資源發出要求,且該來源傳回 COR 標頭,則類型為 corscors 回應與 basic 回應類似,但這些回應會限制您可查看的標頭為 Cache-ControlContent-LanguageContent-TypeExpiresLast-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(function(response) {
    return response.text();
    })
    .then(function(text) {
    console.log('Request successful', text);
    })
    .catch(function(error) {
    log('Request failed', error)
    });

Promise 鏈結

承諾的一大優勢是能夠將兩者鏈結在一起。對於 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(function(data) {
    console.log('Request succeeded with JSON response', data);
    }).catch(function(error) {
    console.log('Request failed', error);
    });

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

如果 Promise 解析,指令碼就會呼叫 json() 方法,從 response.json() 呼叫傳回第二個 Promise,並建立包含剖析 JSON 的物件。如果剖析失敗,Promise 會被拒絕,並且執行擷取陳述式。

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

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(function (data) {
    console.log('Request succeeded with JSON response', data);
    })
    .catch(function (error) {
    console.log('Request failed', error);
    });

在擷取要求時傳送憑證

如要使用 Cookie 等憑證發出擷取要求,請將要求的 credentials 值設為 "include"

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