借鑒:https://segmentfault.com/a/1190000011433064
1、重構公司的后台項目,偶然間在git上看見別人的項目中用到fetch,查了下才知道是ES6的新特性,和ajax的功能相似,都是實現請求,但是多少有些兼容性問題。
(1)fetch和XMLHttpRequest
fetch就是XMLHttpRequest的一種替代方案,除了XMLHttpRequest對象來獲取后台的數據之外,還可以使用一種更優的解決方案fetch。 (2)如何獲取fetch
https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API 使用第三方的ployfill來實現只會fetch https://github.com/github/fetch (3)fetch的helloworld
// 通過fetch獲取百度的錯誤提示頁面 fetch('https://www.baidu.com/search/error.html') // 返回一個Promise對象 .then((res)=>{ return res.text() // res.text()是一個Promise對象 }) .then((res)=>{ console.log(res) // res是最終的結果 }) (4)GET請求
// 通過fetch獲取百度的錯誤提示頁面 fetch('https://www.baidu.com/search/error.html', { method: 'GET' }) .then((res)=>{ return res.text() }) .then((res)=>{ console.log(res) }) GET請求的參數傳遞 GET請求中如果需要傳遞參數怎么辦?這個時候,只能把參數寫在URL上來進行傳遞了。 // 通過fetch獲取百度的錯誤提示頁面 fetch('https://www.baidu.com/search/error.html?a=1&b=2', { // 在URL中寫上傳遞的參數 method: 'GET' }) .then((res)=>{ return res.text() }) .then((res)=>{ console.log(res) }) (5)POST請求
// 通過fetch獲取百度的錯誤提示頁面 fetch('https://www.baidu.com/search/error.html', { method: 'POST' // 指定是POST請求 }) .then((res)=>{ return res.text() }) .then((res)=>{ console.log(res) }) POST請求參數的傳遞 眾所周知,POST請求的參數,一定不能放在URL中,這樣做的目的是防止信息泄露 // 通過fetch獲取百度的錯誤提示頁面 fetch('https://www.baidu.com/search/error.html', { method: 'POST', body: new URLSearchParams([["foo", 1],["bar", 2]]).toString() // 這里是請求對象 }) .then((res)=>{ return res.text() }) .then((res)=>{ console.log(res) }) (6)設置請求的頭信息
一般是表單提交,現默認的提交方式是:Content-Type:text/plain;charset=UTF-8,不合理,下面指定請求方式 // 通過fetch獲取百度的錯誤提示頁面 fetch('https://www.baidu.com/search/error.html', { 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) }) (7)通過接口得到JSON數據
返回的類型:https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch#Body // 通過fetch獲取百度的錯誤提示頁面 fetch('https://www.baidu.com/rec?platform=wise&ms=1&rset=rcmd&word=123&qid=11327900426705455986&rq=123&from=844b&baiduid=A1D0B88941B30028C375C79CE5AC2E5E%3AFG%3D1&tn=&clientWidth=375&t=1506826017369&r=8255', { // 在URL中寫上傳遞的參數 method: 'GET', headers: new Headers({ 'Accept': 'application/json' // 通過頭指定,獲取的數據類型是JSON }) }) .then((res)=>{ return res.json() // 返回一個Promise,可以解析成JSON }) .then((res)=>{ console.log(res) // 獲取JSON數據 }) (8)強制帶Cookie
默認情況下, fetch 不會從服務端發送或接收任何 cookies, 如果站點依賴於維護一個用戶會話,則導致未經認證的請求(要發送 cookies,必須發送憑據頭). // 通過fetch獲取百度的錯誤提示頁面 fetch('https://www.baidu.com/search/error.html', { method: 'GET', credentials: 'include' // 強制加入憑據頭 }) .then((res)=>{ return res.text() }) .then((res)=>{ console.log(res) }) (9)簡單封裝一下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') }
2、下面是封裝好的fetch加兼容性
export default async(url = '', data = {}, type = 'GET', method = 'fetch') => { type = type.toUpperCase(); url = baseUrl + url; if (type == 'GET') { let dataStr = ''; //數據拼接字符串 Object.keys(data).forEach(key => { dataStr += key + '=' + data[key] + '&'; }) if (dataStr !== '') { dataStr = dataStr.substr(0, dataStr.lastIndexOf('&')); url = url + '?' + dataStr; } } if (window.fetch && method == 'fetch') { let requestConfig = { credentials: 'include', method: type, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, mode: "cors", cache: "force-cache" } if (type == 'POST') { Object.defineProperty(requestConfig, 'body', { value: JSON.stringify(data) }) } try { const response = await fetch(url, requestConfig); const responseJson = await response.json(); return responseJson } catch (error) { throw new Error(error) } } else { return new Promise((resolve, reject) => { let requestObj; if (window.XMLHttpRequest) { requestObj = new XMLHttpRequest(); } else { requestObj = new ActiveXObject; } let sendData = ''; if (type == 'POST') { sendData = JSON.stringify(data); } requestObj.open(type, url, true); requestObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); requestObj.send(sendData); requestObj.onreadystatechange = () => { if (requestObj.readyState == 4) { if (requestObj.status == 200) { let obj = requestObj.response if (typeof obj !== 'object') { obj = JSON.parse(obj); } resolve(obj) } else { reject(requestObj) } } } }) } }