查看原文 javascript
fetch
是瀏覽器中發送http請求最流行方式。它不只僅是一個比XMLHttpRequest更好、更符合人體工程學的API,它還帶來了許多使人興奮的新功能,好比響應流、對憑證和CORS請求的更多控制,以及與ServiceWorkers和緩存API的集成java
我本身也在研究並使用它,同時也見證了fetch的成長(原文:普遍使用), 發現即便有經驗的開發者也會犯一些比較常見的錯誤。我認爲這在很大程度上與fetch的API在表面上看起來它的行爲模式都很像jQuery $.ajax、angularJS的$http、 axios等。它們之間有一些重要的區別,而這些區別大多源於fetch做爲底層網絡請求的原型設計jquery
Fetch是基於promise的,所以比較容易想到,若是服務器返回http的錯誤狀態碼,像404或是500,Promise就會被拒絕,就像原始的XMLHttpRequest同樣;但fetch並非這樣的——它僅僅在發生「network error(網絡錯誤)」纔會被拒絕(這是一個使人困惑的術語,但規範是這麼說的)。若是能夠服務器得到http錯誤狀態,則代表服務器正常工做且在處理請求,而「network error(網絡錯誤)」表示根本沒法到達服務器(例如鏈接拒絕或名稱未解析)或請求配置有錯誤(錯誤的請求地址)。
ios
例如, ftp
協議 並不支持fetch,因此它會返回一個被rejected 的 promise :git
fetch('ftp://example.com') .catch(err => console.error('Caught error: ', err))複製代碼
可是請求一個返回404錯誤的URL並有沒有發生錯誤(即相似404這類錯誤fetch返回的並非rejected)angularjs
fetch('https://jsonplaceholder.typicode.com/404')
.then(res => console.log('response: ', res)) .catch(console.error)複製代碼
我想對大部分開發者來講,http返回的錯誤對web應用程序處理一個rejected的promise是很是有用的。爲此(fetch對http錯誤的處理方式),咱們僅僅須要對驗證 ok
屬性的值 ,若是 ok
es6
的值爲false
,則 rejectgithub
fetch('https://jsonplaceholder.typicode.com/404')
.then(res => {
if(res.ok) {
return res;
} else {
throw Error(`Request rejected with status ${res.status}`);
}})
.catch(console.error)複製代碼
與XHR不一樣,fetch在默認狀況下不包括請求中的任何cookie。所以,若是針對您的API的請求須要基於cookie的受權(大多數web應用程序都須要),那麼必須有這個選項,不然您的調用可能會返回401未受權。
web
這很是簡單:ajax
fetch('/url', { credentials: 'include' })複製代碼
注意,若是您正在使用fetch polyfill,那麼(不幸的是)您可能會偶爾地忘記這一點,一切看起來就好像你已經正在使用credentials: 'include'
同樣,這是由於它只是在底層使用XHR,而XHR自動具備這種行爲。
$http, axios和其它http工具在默認狀況下會爲您設置此頭,所以很容易忘記。
fetch('https://cameronnokes.com/slack-ron-swanson-quote-bot/ron', {
method: 'POST',
body: JSON.stringify({text: 'bacon'}),
headers: {'Content-Type': 'application/json'}})
.then(res => res.json())
.then(console.log)複製代碼
若是不包含該頭,服務器可能會返回一個400
個Bad Request
,由於endpoint
不支持純文本內容類型,或者沒法處理這種文本的body,這取決於API的實現。但不管如何,您的API可能會返回HTTP錯誤狀態。
我常常看到相似這樣的代碼:
fetch('/endpoint?foo=${n > 1 ? 123 : 456}&bar=abc&query=${encodeURIComponent(someString || '')}複製代碼
這並不徹底是糟糕的,但我認爲若是咱們讓新的URLSearchParams類和少許lodash爲咱們作更多的工做,它會更容易閱讀,更少出錯。
URLSearchParams類很是棒,能夠正確地處理編碼、將對象鏈接到字符串等等。我認爲這樣更容易閱讀和維護。
Fetch很棒,可是要負責任地去享受
======================= 如下爲譯者添加=========================
伴隨fetch的問世及發展,目前在生產環境使用fetch的企業愈來愈多。開源社區上有關fetch polyfilll已經多款供選,又因其基於Promise,如下能夠完美的解決其兼容性問題(特別是IE),僅參考:
因爲 IE8 是 ES3,須要引入 ES5
的
polyfill
: es5-shim
, es5-sham
引入 Promise
的 polyfill
: es6-promise
引入 fetch
探測庫:fetch-detector
引入 fetch
的 polyfill
: fetch-ie8
可選:若是你還使用了 jsonp
,引入 fetch-jsonp
可選:開啓 Babel
的 runtime
模式,如今就使用 async
/await
fetch 的好處無需多語,但fetch也存在一些問題,例如不支持timeout,不支持 progress,特別是fetch在跨域問題上與傳統跨域的處理方式的區別,社區中都對應的解決方案,此文不一一列舉。正如原諒做者所言:負責任地去享受