fetch()
可讓您發出類似 XMLHttpRequest (XHR) 的網路要求。主要差別在於 Fetch API 使用 Promise,而 Promise 具有更簡易的 API,有助於避免 XMLHttpRequest API 中的複雜回呼。
如果您從未使用過 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 標頭,則類型為 cors
。cors
回應與 basic
回應類似,但這些回應會限制您可查看的標頭為 Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
和 Pragma
。
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()
選項中設定 method
和 body
參數:
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'
})