前後端資料互動(四)——fetch 請求詳解

前端人發表於2021-09-07

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 物件如圖:

前後端資料互動(四)——fetch 請求詳解

 

  • status - http狀態碼,範圍在100-599之間
  • statusText - 伺服器返回狀態文字描述
  • ok - 返回布林值,如果狀態碼2開頭的,則true,反之false
  • headers - 響應頭
  • body - 響應體。響應體內的資料,根據型別各自處理。
  • type - 返回請求型別。
  • redirected - 返回布林值,表示是否發生過跳轉。

1.3、讀取內容方法

response 物件根據伺服器返回的不同型別資料,提供了不同的讀取方法。分別有:

  1. response.text() -- 得到文字字串
  2. response.json() - 得到 json 物件
  3. response.blob() - 得到二進位制 blob 物件
  4. response.formData() - 得到 fromData 表單物件
  5. 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 請求詳解

 

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 欄位來判斷。

相關文章