fetch API 簡單解讀
http://f2e.souche.com/blog/fetch-api-jie-du/?utm_source=tuicool&utm_medium=referral
在我們日常的前端開發中,XMLHttpRequest
是必不可少會遇到的一個東東。XHR
最初是由微軟引入其 MSXML
的,Web
開發者需要通過 ActiveX 去呼叫,而後,Mozilla 開發者開發了一個近似的東西,為了方便在 JavaScript 中使用,才用 XMLHttpRequest
為名的物件封裝了一下。使用 XHR
發起一個請求,大致程式碼就會如下所示:
// 首先,需要些一些特徵檢測來做下瀏覽器相容 if (window.XMLHttpRequest) { request = new XMLHttpRequest(); } else if (window.ActiveXObject) { try { request = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { request = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {} } } // 然後開啟一個請求 request.open('GET', 'https://nodejs.org/api/http.json', true); // 真正意義上的請求 request.send(null); request.addEventListener('load', function() { // 處理返回結果 })
以上的程式碼,相信每個前端開發都有寫過,然而就算不寫那一段長長的相容程式碼,光是後面發起請求的那段程式碼,也會讓人覺得頭大。就更不用說所謂的 XMLHttpRequest
,其實現在幾乎沒人用
XML 做瀏覽器短的資料互動形式了。
儘管眾多三方框架已經封裝了一些好用的 api,例如 jQuery.ajax()
,angular.js
的 $http
,但是如果有個更簡單的方法呢?
Syntax
fetch()
的語法很簡單,如下所示:
fetch(input, init).then(function(response) { ... });
其中:
input
引數,即可以直接傳入一個
url,也可以傳入一個 Request
物件;
init
引數是可選,是一個包含了請求方法,請求頭部,請求主體,模式,憑證,快取模式等配置的物件。
從語法中可以看到,fetch()
API
會返回一個 Promise。
因此,開頭所提到的例子,可以修改成這樣:
fetch('https://nodejs.org/api/http.json').then(function(response) {
return // 響應處理
}).catch(function(err) {
// 捕獲錯誤
});
除了普通的 get 請求,發起一個表單 POST 請求也是相當簡單:
fetch('/post/some/data', { method: 'post', body: new FormData(document.querySelector('#form')) });
同理,如果是 json 格式的資料的話:
fetch('/post/some/data', {
method: 'post',
body: JSON.stringify({ user: 'lisposter', pwd: 'souche.com'})
});
響應處理
與上述 Request
對應的,Fetch
API 還對應有一個 Response
用於表示響應結果,Response
,是一個 Stream 物件,其提供了眾多便利的屬性及方法以供開發者處理。方法一般會返回一個
Promise,舉個例子,處理 json 資料。簡單示例:
fetch('https://nodejs.org/api/http.json')
.then(function(response) {
return response.json();
})
.then(function(json) {
// 此處的 json 已經被處理為 json 物件
})
.catch(function(err) {
// 捕獲錯誤
});
這裡,你當然也可以選擇使用傳統的 JSON.parse()
,但無疑,使用 .json()
方法更加方便快捷,適合在
Promise 中使用。
同理,如果你希望處理請求結果為純文字,那麼 Response.text()
將會很有幫助。除此之外,還有 .blob()
, formData()
等方法可供使用。Fetch
API 所支援的響應型別有如下幾種:
從 Response 的屬性中,我們也能輕易提取到響應頭部及 Metadata 的相關資訊:
fetch('https://nodejs.org/api/http.json').then(function(response) {
console.log(response.status);
console.log(response.statusText);
console.log(response.url);
console.log(response.type);
console.log(response.headers);
// 獲取頭部資訊需要使用 .get()
console.log(response.headers.get('Content-Type'));
})
其中,response.headers 就是一個 Header 型別的物件,我們可以使用 Headers 類提供的各種方法來操作,除了上面程式碼中的 .get()
方法外,Headers
還有 .has()
方法,用於檢查是否包含某個頭部資訊;.getAll()
方法,將制定的頭部資訊以陣列形式全部返回,等等,具體可以參考 Headers 型別文件
響應型別
每當我們用 fetch 發起一個請求,其響應都會被賦予一個響應型別,'basic','cors' 或者 'opaque'。
如果請求是同源的,那麼響應型別就是 'basic',如果跨域的請求,則是 'cors',如果對非同源的資源發起一個請求,並且其沒有返回 CORS 頭的話,則是 'opaque' 型別。'opaque' 型別的響應我們將不能讀取所返回的資料或者檢視請求的狀態,也就是說,我們壓根沒辦法知道請求是否成功了。
我們可以在發起請求的時候,指定一個模式來確保只有相應的請求會被允許:
same-origin
: 只有同源的請求才會被允許。cors
: 允許同源或者非同源但是返回正確 CORS 頭部的請求。cors-with-forced-preflight
: 在正式請求之前,總是先發起一個 preflight 檢查。no-cors
: 用以發起非同源又沒有返回 CORS 頭的請求。
注意:因為 Cache API 還沒有在 window 物件中實現,因此,目前 fetch api 並沒有支援從 window 域中發起 no-cors 請求,但是你可以在 Service Worker 中使用。
投入使用
Fetch API 並沒有完全完成,因此,瀏覽器對其支援也不完全,在實際使用的時候還需要注意相容問題,可以通過特性檢查,檢查 Headers, Request, Response 或者 fetch 是否存在來判斷瀏覽器的支援情況。也可以參考 Can I Use 提供的相容情況列表。你也可以使用 GitHub 提供的 polyfill,他可以相容到最低 IE9,相信可以滿足大多數的情況了。
在未來,Cache API 的實現完成後,Fetch API 將能很好地處理離線狀態下的請求,這應該是大家最期待的特性了。