Fetch總結

2019第二發javascript

說明

因爲 Fetch API 是基於 Promise 設計,有必要先學習一下 Promise。舊瀏覽器不支持 Promise,須要使用 polyfill es6-promisehtml

若是不支持fetch也沒有問題,可使用第三方的ployfill來實現只會fetch:whatwg-fetch 這個用的人多。java

開始

發送一個json請求git

XHR方式

var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'json';
xhr.onload = function() {
  console.log(xhr.response);
};
xhr.onerror = function() {
  console.log("Oops, error");
};
xhr.send();
複製代碼

fetch方式

fetch(url).then(function(res) {
    return res.json()
}).then(function(data) {
    console.log(data);
}).catch(function(e) {
    console.error(e)
})
複製代碼

或者:es6

fetch(url).then(response => response.json())
  .then(data => console.log(data))
  .catch(e => console.error(e))
複製代碼

再或者:github

async/await 是很是新的 API,屬於 ES7json

try{
    let res = await fetch(url)
    let data = await res.json()
    console.log(data)
}catch(e) {
    console.error(e)
}
複製代碼

使用 await 後,寫異步代碼就像寫同步代碼同樣爽。await 後面能夠跟 Promise 對象,表示等待 Promise resolve() 纔會繼續向下執行,若是 Promise 被 reject() 或拋出異常則會被外面的 try...catch 捕獲。segmentfault

fetch GET請求初步

fetch(url, {
    method: 'GET'
})
.then((res) => {
    return res.text()
})
.then((res) => {
    console.log(res)
})
複製代碼

fetch GET請求的參數傳遞

fetch(url + '?a=1&b=2', { // 在URL中寫上傳遞的參數
    method: 'GET'
})
.then((res) => {
    return res.text()
})
.then((res) => {
    console.log(res)
})
複製代碼

fetch POST請求初步

fetch(url, {
    method: 'POST' // 指定是POST請求
})
.then((res)=>{
    return res.text()
})
.then((res)=>{
    console.log(res)
})
複製代碼

fetch POST請求參數的傳遞

let formData = new FormData()
formData.append('foo', 1)
formData.append('bar', 2)
fetch(url, {
    method: 'POST',
    body: formData,// 這裏是請求對象
})
.then((res) => {
    return res.text()
})
.then((res) => {
    console.log(res)
})
複製代碼

fetch 設置請求的頭信息

在POST提交的過程當中,通常是表單提交,但是,通過查詢,發現默認的提交方式是:Content-Type:text/plain;charset=UTF-8,這個顯然是不合理的。後端

fetch(url, {
    method: 'POST',
    headers: new Headers({
      'Content-Type': 'application/x-www-form-urlencoded' // 指定提交方式爲表單提交
    }),
    body: new URLSearchParams([["foo", 1],["bar", 2]]).toString()
  })
  .then((res)=>{
    return res.text()
  })
  .then((res)=>{
    console.log(res)
  })
複製代碼

fetch 經過接口獲得JSON數據

上面全部的例子中都是返回一個文本跨域

fetch(
    url, { // 在URL中寫上傳遞的參數
        method: 'GET',
        headers: new Headers({
            'Accept': 'application/json' // 經過頭指定,獲取的數據類型是JSON
        })
    })
.then((res) => {
    return res.json() // 返回一個Promise,能夠解析成JSON
})
.then((res) => {
    console.log(res) // 獲取JSON數據
})
複製代碼

fetch 強制帶Cookie

默認狀況下, fetch 不會從服務端發送或接收任何 cookies, 若是站點依賴於維護一個用戶會話,則致使未經認證的請求(要發送 cookies,必須發送憑據頭). fetch(url, { method: 'GET', credentials: 'include' // 強制加入憑據頭 })

fetch 簡單封裝一下

/** * 將對象轉成 a=1&b=2的形式 * @param obj 對象 */
function obj2String(obj, arr = [], idx = 0) {
  for (let item in obj) {
    arr[idx++] = [item, obj[item]]
  }
  return new URLSearchParams(arr).toString()
}

/** * 真正的請求 * @param url 請求地址 * @param options 請求參數 * @param method 請求方式 */
function commonFetcdh(url, options, method = 'GET') {
  const searchStr = obj2String(options)
  let initObj = {}
  if (method === 'GET') { // 若是是GET請求,拼接url
    url += '?' + searchStr
    initObj = {
      method: method,
      credentials: 'include'
    }
  } else {
    initObj = {
      method: method,
      credentials: 'include',
      headers: new Headers({
        'Accept': 'application/json',
        'Content-Type': 'application/x-www-form-urlencoded'
      }),
      body: searchStr
    }
  }
  fetch(url, initObj).then((res) => {
    return res.json()
  }).then((res) => {
    return res
  })
}

/** * GET請求 * @param url 請求地址 * @param options 請求參數 */
function GET(url, options) {
  return commonFetcdh(url, options, 'GET')
}

/** * POST請求 * @param url 請求地址 * @param options 請求參數 */
function POST(url, options) {
  return commonFetcdh(url, options, 'POST')
}
複製代碼
GET('https://www.baidu.com/search/error.html', {a:1,b:2})
POST('https://www.baidu.com/search/error.html', {a:1,b:2})
複製代碼

支持

支持
原生支持率並不高,幸運的是,引入下面這些 polyfill 後能夠完美支持 IE8+ :

常見問題

  • Fetch 請求默認是不帶 cookie 的,須要設置 fetch(url, {credentials: 'include'})
  • 服務器返回 400,500 錯誤碼時並不會 reject,只有網絡錯誤這些致使請求不能完成時,fetch 纔會被 reject。
  • 全部版本的 IE 均不支持原生 Fetch,fetch-ie8 會自動使用 XHR 作 polyfill。但在跨域時有個問題須要處理。IE8, 9 的 XHR 不支持 CORS 跨域。
  • Response返回一個被解析後的promise對象和數據,有這些解析方式:arrayBuffer()、blob()、、json()、text()、formData()

參考

  1. 傳統 Ajax 已死,Fetch 永生
  2. fetch,終於認識你

總結

  • 語法簡潔,更加語義化
  • 基於標準 Promise 實現,支持 async/await
  • 同構方便,使用isomorphic-fetch

注:同構(isomorphic/universal)就是使先後端運行同一套代碼的意思,後端通常是指 NodeJS 環境。

相關文章
相關標籤/搜索