fetch 是 XMLHttpRequest 的升級版,使用js腳本發出網絡請求,但是與 XMLHttpRequest 不同的是,fetch 方式使用 Promise,相比 XMLHttpRequest 更加簡潔。所以我們告別XMLHttpRequest,引入 fetch 如何使用?
一、fetch介紹
fetch() 是一個全局方法,提供一種簡單,合理的方式跨網絡獲取資源。它的請求是基於 Promise 的,需要詳細學習 Promise ,請點擊《 Promise詳解 》。它是專門為了取代傳統的 xhr 而生的。
1.1、fetch使用語法
fetch(url,options).then((response)=>{ //處理http響應 },(error)=>{ //處理錯誤 })
url :是發送網絡請求的地址。
options:發送請求參數,
- body - http請求參數
- mode - 指定請求模式。默認值為cros:允許跨域;same-origin:只允許同源請求;no-cros:只限於get、post和head,並且只能使用有限的幾個簡單標頭。
- cache - 用戶指定緩存。
- method - 請求方法,默認GET
- signal - 用於取消 fetch
- headers - http請求頭設置
- keepalive - 用於頁面卸載時,告訴瀏覽器在后台保持連接,繼續發送數據。
- credentials - cookie設置,默認omit,忽略不帶cookie,same-origin同源請求帶cookie,inclue無論跨域還是同源都會帶cookie。
1.2、response 對象
fetch 請求成功后,響應 response 對象如圖:

- status - http狀態碼,范圍在100-599之間
- statusText - 服務器返回狀態文字描述
- ok - 返回布爾值,如果狀態碼2開頭的,則true,反之false
- headers - 響應頭
- body - 響應體。響應體內的數據,根據類型各自處理。
- type - 返回請求類型。
- redirected - 返回布爾值,表示是否發生過跳轉。
1.3、讀取內容方法
response 對象根據服務器返回的不同類型數據,提供了不同的讀取方法。分別有:
- response.text() -- 得到文本字符串
- response.json() - 得到 json 對象
- response.blob() - 得到二進制 blob 對象
- response.formData() - 得到 fromData 表單對象
- response.arrayBuffer() - 得到二進制 arrayBuffer 對象
上述 5 個方法,返回的都是 promise 對象,必須等到異步操作結束,才能得到服務器返回的完整數據。
1.4、response.clone()
stream 對象只能讀取一次,讀取完就沒了,這意味着,上邊的五種讀取方法,只能使用一個,否則會報錯。
因此 response 對象提供了 clone() 方法,創建 respons 對象副本,實現多次讀取。如下:將一張圖片,讀取兩次:
const response1 = await fetch('flowers.jpg'); const response2 = response1.clone(); const myBlob1 = await response1.blob(); const myBlob2 = await response2.blob(); image1.src = URL.createObjectURL(myBlob1); image2.src = URL.createObjectURL(myBlob2);
1.5、response.body()
body 屬性返回一個 ReadableStream 對象,供用戶操作,可以用來分塊讀取內容,顯示下載的進度就是其中一種應用。
const response = await fetch('flower.jpg'); const reader = response.body.getReader(); while(true) { const {done, value} = await reader.read(); if (done) { break; } console.log(`Received ${value.length} bytes`) }
response.body.getReader() 返回一個遍歷器,這個遍歷器 read() 方法每次都會返回一個對象,表示本次讀取的內容塊。
二、請求時 POST 和 GET 分別處理
請求方式不同,傳值方式也不同。xhr 會分別處理 get 和 post 數據傳輸,還有請求頭設置,同樣 fetch 也需要分別處理。
2.1、get 方式
只需要在url中加入傳輸數據,options中加入請求方式。如下面代碼所示:
<input type="text" id="user"><br> <input type="password" id="pas"><br> <button onclick="login()">提交</button> <script> function login(){ fetch(`http://localhost:80/fetch.html?user=${user.value}&pas=${pas.value}`,{ method:'GET' }).then(response=>{ console.log('響應',response) }) } </script>
2.2、post 方式
使用 post 發送請求時,需要設置請求頭、請求數據等。
將上個實例,改寫成 post 方式提交數據,代碼如下:
fetch(`http://localhost:80/ES6練習題/53fetch.html`,{ method:'POST', headers:{ 'Content-Type':'application/x-www-form-urlencoded;charset=UTF-8' }, body:`user=${user.value}&pas=${pas.value}` }).then(response=>{ console.log('響應',response) })
如果是提交json數據時,需要把json轉換成字符串。如
body:JSON.stringify(json)
如果提交的是表單數據,使用 formData轉化下,如:
body:new FormData(form)
上傳文件,可以包含在整個表單里一起提交,如:
const input = document.querySelector('input[type="file"]'); const data = new FormData(); data.append('file', input.files[0]); data.append('user', 'foo'); fetch('/avatars', { method: 'POST', body: data });
上傳二進制數據,將 bolb 或 arrayBuffer 數據放到body屬性里,如:
let blob = await new Promise(resolve => canvasElem.toBlob(resolve, 'image/png') ); let response = await fetch('/article/fetch/post/image', { method: 'POST', body: blob });
三、fetch 常見坑
3.1、fetch兼容性
fetch原生支持率如圖:

fetch 是相對較新的技術,IE瀏覽器不支持,還有其他低版本瀏覽器也不支持,因此如果使用fetch時,需要考慮瀏覽器兼容問題。
解決辦法:引入 polyfill 完美支持 IE8 以上。
- 由於 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
polyfill 的原理就是探測fetch是否支持,如果不支持則用 xhr 實現。支持 fetch 的瀏覽器,響應中文會亂碼,所以使用 fetch-detector 和 fetch-ie8 解決亂碼問題。
3.2、fetch默認不帶cookie
傳遞cookie時,必須在header參數內加上 credentials:'include',才會像 xhr 將當前cookie 帶有請求中。
3.3、異常處理
fetch 不同於 xhr ,xhr 自帶取消、錯誤等方法,所以服務器返回 4xx 或 5xx 時,是不會拋出錯誤的,需要手動處理,通過 response 中的 status 字段來判斷。