Ajax是基於XMLHttpRequest 封裝的網絡請求API. XMLHttpRequest 並不是專為Ajax而設計的. 雖然各種框架對 XHR 的封裝已經足夠好用, 但我們可以做得更好。更好用的API是 fetch
。下面簡單介紹 window.fetch
方法, 在最新版的 Firefox 和 Chrome 中已經提供支持。
XMLHttpRequest
使用XHR的方式大致如下:
// 獲取 XHR 非常混亂! if (window.XMLHttpRequest) { // Mozilla, Safari, ... request = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE try { request = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { request = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {} } } // 打開連接, 發送數據. request.open('GET', 'https://davidwalsh.name/ajax-endpoint', true); request.send(null);
我們可以看出, XHR 其實是很雜亂的; 當然, 通過 JavaScript 框架可以很方便地使用XHR。
fetch
的基本使用
// url (必須), options (可選) fetch('/some/url', { method: 'get' }).then(function(response) { }).catch(function(err) { // 出錯了;等價於 then 的第二個參數,但這樣更好用更直觀 :( });
fetch API 也使用了Promise來處理結果/回調
自定義請求頭信息極大地增強了請求的靈活性。我們可以通過 new Headers()
來創建請求頭:
// 創建一個空的 Headers 對象,注意是Headers,不是Header var headers = new Headers(); // 添加(append)請求頭信息 headers.append('Content-Type', 'text/plain'); headers.append('X-My-Custom-Header', 'CustomValue'); // 判斷(has), 獲取(get), 以及修改(set)請求頭的值 headers.has('Content-Type'); // true headers.get('Content-Type'); // "text/plain" headers.set('Content-Type', 'application/json'); // 刪除某條請求頭信息(a header) headers.delete('X-My-Custom-Header'); // 創建對象時設置初始化信息 var headers = new Headers({ 'Content-Type': 'text/plain', 'X-My-Custom-Header': 'CustomValue' });
可以使用的方法包括: append, has, get, set, 以及 delete 。需要創建一個 Request
對象來包裝請求頭:
var request = new Request('/some-url', { headers: new Headers({ 'Content-Type': 'text/plain' }) }); fetch(request).then(function() { /* handle response */ });
Request 簡介
Request 對象表示一次 fetch 調用的請求信息。傳入 Request 參數來調用 fetch, 可以執行很多自定義請求的高級用法:
method
- 支持GET
,POST
,PUT
,DELETE
,HEAD
url
- 請求的 URLheaders
- 對應的Headers
對象referrer
- 請求的 referrer 信息mode
- 可以設置cors
,no-cors
,same-origin
credentials
- 設置 cookies 是否隨請求一起發送。可以設置:omit
,same-origin
redirect
-follow
,error
,manual
integrity
- subresource 完整性值(integrity value)cache
- 設置 cache 模式 (default
,reload
,no-cache
)
Request
的示例如下:
var request = new Request('/users.json', { method: 'POST', mode: 'cors', redirect: 'follow', headers: new Headers({ 'Content-Type': 'text/plain' }) }); // 使用! fetch(request).then(function() { /* handle response */ });
只有第一個參數 URL 是必需的。在 Request
對象創建完成之后, 所有的屬性都變為只讀屬性. 請注意, Request
有一個很重要的 clone
方法, 特別是在 Service Worker API 中使用時 —— 一個 Request 就代表一串流(stream), 如果想要傳遞給另一個 fetch
方法,則需要進行克隆。
fetch
的方法簽名(signature,可理解為配置參數), 和 Request
很像, 示例如下:
fetch('/users.json', { method: 'POST', mode: 'cors', redirect: 'follow', headers: new Headers({ 'Content-Type': 'text/plain' }) }).then(function() { /* handle response */ });
Response 簡介
Response 代表響應, fetch 的 then
方法接收一個 Response
實例, 當然你也可以手動創建 Response
對象 —— 比如在 service workers 中可能會用到. Response 可以配置的參數包括:
type
- 類型,支持:basic
,cors
url
useFinalURL
- Boolean 值, 代表url
是否是最終 URLstatus
- 狀態碼 (例如:200
,404
, 等等)ok
- Boolean值,代表成功響應(status 值在 200-299 之間)statusText
- 狀態值(例如:OK
)headers
- 與響應相關聯的 Headers 對象.
// 在 service worker 測試中手動創建 response // new Response(BODY, OPTIONS) var response = new Response('.....', { ok: false, status: 404, url: '/' }); // fetch 的 `then` 會傳入一個 Response 對象 fetch('/') .then(function(responseObj) { console.log('status: ', responseObj.status); });
Response
提供的方法如下:
clone()
- 創建一個新的 Response 克隆對象.error()
- 返回一個新的,與網絡錯誤相關的 Response 對象.redirect()
- 重定向,使用新的 URL 創建新的 response 對象..arrayBuffer()
- Returns a promise that resolves with an ArrayBuffer.blob()
- 返回一個 promise, resolves 是一個 Blob.formData()
- 返回一個 promise, resolves 是一個 FormData 對象.json()
- 返回一個 promise, resolves 是一個 JSON 對象.text()
- 返回一個 promise, resolves 是一個 USVString (text).
處理 JSON響應
假設需要請求 JSON —— 回調結果對象 response 中有一個json()
方法,用來將原始數據轉換成 JavaScript 對象:
fetch('https://davidwalsh.name/demo/arsenal.json').then(function(response) { // 轉換為 JSON return response.json(); }).then(function(j) { // 現在, `j` 是一個 JavaScript object console.log(j); });
當然這很簡單 , 只是封裝了 JSON.parse(jsonString)
而已, 但 json
方法還是很方便的。
處理基本的Text / HTML響應
JSON 並不總是理想的請求/響應數據格式, 那么我們看看如何處理 HTML或文本結果:
fetch('/next/page') .then(function(response) { return response.text(); }).then(function(text) { // })
處理Blob結果
如果你想通過 fetch 加載圖像或者其他二進制數據, 則會略有不同:
fetch('flowers.jpg') .then(function(response) { return response.blob(); }) .then(function(imageBlob) { document.querySelector('img').src = URL.createObjectURL(imageBlob); });
fetch
是個很實用的API , 當前還不允許取消請求, 這使得很多程序員暫時不會考慮它。
新的 fetch
API 比起 XHR 更簡單也更智能。畢竟,它就是專為AJAX而設計的, 具有后發優勢. 而我已經迫不及待地使用了, 即使現在兼容性還不是那么好!IE並不兼容fetch, 我在項目中也遇到這個問題在引用的fetch的地方引用 isomorphic-fetch 解決。
默認不帶 cookie
原文鏈接:https://juejin.im/entry/574512b7c26a38006c43567c