[WebAPIs] Fetch API
keywords: Fetch API
, AJAX
Fetch API Example @ Gist
TD;DR
// Simple Get Request
fetch('<resourceURL>', init)
.then((response) => response.json()) // response.ok, response.status, response.statusText
.then((json) => console.log(json))
.catch((error) => console.log(error));
重要概念
- 要留意的是,即使回應是 404 該 Promise 依然會被 resolve,只有在該請求沒辦法被完成時(例如,無網路連線),才會被
reject
進而進到catch
,因此,需要自己判斷response.ok
,如果不ok
則透過throw
讓它進入catch
。 - 除非有在選項中帶入
credentials
的設定,否則fetch()
預設不會傳送 cross-origin cookies
With Error Handling:
fetch('<resourceURL>', init)
.then((response) => {
if (response.ok) {
return response.json();
}
throw new Error('Network response was not ok.');
})
.then((data) => console.log(json))
.catch((error) => console.log(error));
Example:
See the Pen Fetch API sandbox by PJCHEN (@PJCHENder) on CodePen.
Fetch API
最簡單使用 fetch()
的方式就是帶入一個參數,讓入你想要發送請求的資源(resource),接著會回傳包含 Response
物件的 Promise。但這個 Response 只是 HTTP Response,我們可以透過 json()
方法來取出 response 中的 JSON 部分:
// Example GET method request
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then((response) => response.json())
.then((json) => console.log(json))
.catch((error) => console.log(error));
Init Options
在 fetch()
的第二個參數中可以放入其他相關的設定:
// Example POST method implementation
let data = {
title: 'foo',
body: 'bar',
userId: 1,
};
postData('https://jsonplaceholder.typicode.com/posts', data)
.then((data) => console.log(data)) // JSON from `response.json()` call
.catch((error) => console.error(error));
const init = {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
body: JSON.stringify(data), // must match 'Content-Type' header
headers: {
'user-agent': 'Mozilla/4.0 MDN Example',
'content-type': 'application/json; charset=UTF-8',
Accept: 'application/json',
},
cache: 'no-cache',
mode: 'cors', // no-cors, cors, *same-origin
redirect: 'follow', // *manual, follow, error
referrer: 'no-referrer', // *client, no-referrer
};
function postData(url, data) {
// Default options are marked with *
return fetch(url, init).then((response) => response.json()); // parses response to JSON
}
/* will return
{
id: 101,
title: 'foo',
body: 'bar',
userId: 1
}
*/
HEAD Method:在 HTTP Method 中,HEAD 方法和 GET 方法的效果一樣,差別只在於透過 HEAD 方法拿到的
response.body
會是空的,通常用在只需要取得檔案的 metadata 時使用。
Response
在透過 fetch API 取得的 response
中包含一些可用的屬性:
response.ok
:如果回應的狀態介於 200-299 之間,則會是true
response.status
:回應狀態代碼response.statusText
response.redirected
:是否轉址,回傳true
或false
response.url
:發送請求的 url
另外提供了一些可用的方法:
response.json()
response.blob()
response.text()
response.arrayBuffer()
response.formData()
Response Interface @ MDN - Web APIs
範例程式碼
Fetch API Sandbox @ PJCHENder CodePen
// Example
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
// Read the response as json.
return response.json();
})
.then((responseAsJson) => {
// Do stuff with the JSON
console.log(responseAsJson);
})
.catch((error) => {
console.log('Looks like there was a problem: \n', error);
});
如果在 Promise 中需要串連的方法較多,可以考慮把方法抽出來:
// Example
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(validateResponse)
.then(parseResponseToJSON)
.then(doSomething)
.catch(errorHandler);
function validateResponse(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
function parseResponseToJSON(response) {
return response.json();
}
function doSomething(data) {
console.log(data);
}
function errorHandler(error) {
console.log(error);
}
其他
檢驗瀏覽器是否支援 fetch
if (!('fetch' in window)) {
console.log('Fetch API not found, try including the polyfill');
return;
}
// We can safely use fetch from now on
使用 Fetch 取得圖片(blob)
在透過 fetch
取得圖片時,會得到的是 blob
物件,因此需要使用 response.blob()
方法:
fetchImage('https://fakeimg.pl/250x100/');
function fetchImage(imageURL) {
fetch(imageURL)
.then(validateResponse)
.then(parseResponseToBlob)
.then(appendImage)
.catch(errorHandler);
}
function validateResponse(response) {
if (response.ok) {
return response;
}
throw Error(response.statusText);
}
function parseResponseToBlob(response) {
return response.blob();
}
function appendImage(blob) {
const img = new Image(250, 100);
img.src = URL.createObjectURL(blob);
document.querySelector('body').appendChild(img);
}
function errorHandler(error) {
console.log(error);
}
使用 POST 傳送 form data
透過 new FormData()
的方法,可以將 HTML 中的表單元素傳送到後端:
// Assuming an HTML <form> with id of 'myForm'
fetch('some-url/comment', {
method: 'POST',
body: new FormData(document.getElementById('myForm')),
});
自訂標頭(Headers)
透過 new Header()
的方法,可以為 Fetch Request 建立自訂的標頭(Header):
var myHeaders = new Headers({
'Content-Type': 'text/plain',
'X-Custom-Header': 'hello world',
});
fetch('/some-url', {
headers: myHeaders,
});
注意:
Content-Length
和Origin
等標頭基於安全理由是無法被修改的。設置客制化標頭時,瀏覽器會自動發送預檢請求(preflight request)。