相關文檔鏈接 https://developer.mozilla.org/zh-CN/docs/Web/API/fetch https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch https://developer ...
相關文檔鏈接
https://developer.mozilla.org/zh-CN/docs/Web/API/fetch
https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch
https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/readyState
https://developer.mozilla.org/zh-CN/docs/Web/Guide/AJAX
一、ajax 與 fetch 區別
- ajax是用對象來請求數據的,而fetch是基於Promise設計的,是原生js,是一個windows全局方法
- 當接收到一個代表錯誤的 HTTP 狀態碼時,如404 或 500,從fetch()返回的 Promise 不會被標記為 reject。相反,它會將 Promise 狀態標記為 resolve (如果響應的 HTTP 狀態碼不在 200 - 299 的範圍內,則設置 resolve 返回值的
ok
屬性為 false ),僅當網路故障時或請求被阻止時,才會標記為 reject。 fetch預設不帶
cookie,除非你使用了 credentials 的初始化選項。(自 2018 年 8 月以後,預設的 credentials 政策變更為same-origin
。)- 所有的IE瀏覽器都不會支持 fetch()方法
- fetch沒有辦法原生監測請求的進度,而XMLHttpRequest可以
- fetch不支持
abort
,不支持超時控制,使用setTimeout
及Promise.reject
的實現超時控制並不能阻止請求過程繼續在後臺運行,造成了流量的浪費。
二、ajax、fecth與axios
fetch
全局的 fetch()
方法用於發起獲取資源的請求。它返回一個 promise,這個 promise 會在請求響應後被 resolve,並傳回 Response
對象。
當遇到網路錯誤時,fetch()
返回的 promise 會被 reject,並傳回 TypeError
,雖然這也可能因為許可權或其它問題導致。成功的 fetch() 檢查不僅要包括 promise 被 resolve,還要包括 Response.ok
屬性為 true。HTTP 404 狀態並不被認為是網路錯誤。
fetch
是低層次的API,代替XHR
,可以輕鬆處理各種格式,非文本化格式。可以很容易的被其他技術使用,例如Service Workers
。
優勢:跨域的處理
在配置中,添加mode: 'no-cors'
就可以跨域了
fetch
目前遇到的問題:
fetch
只對網路請求報錯,對400
,500
都當做成功的請求,需要封裝去處理fetch
預設不會帶cookie
,需要添加配置項。fetch
不支持abort
,不支持超時控制,使用setTimeout
及Promise.reject
的實現超時控制並不能阻止請求過程繼續在後臺運行,造成了流量的浪費。fetch
沒有辦法原生監測請求的進度,而XHR
可以。
一個簡單的get 、 post請求:
fetch('https://www.baidu.com')
.then(resp=>resp.text()) // 轉換成文本對象
.then(resp=>console.log(resp)) // 輸出請求內容
.catch(error => console.error(error));
fetch('https://www.easy-mock.com',{method:"post"})
.then(resp=>resp.json()) //轉換成Json對象
.then(resp=>console.log(resp)) //輸出Json內容
.catch(error => console.error(error));
綜合請求:
let arr = [{name: "haha", detail:"123"}]; fetch("url", { method: "post", headers: { "Content-Type": "application/json" //"Accept":"allication/json" }, mode: "cors", // cors、no-cors 或者 same-origin 解決跨域問題 credentials: "include", // omit、include、same-origin(預設)。為了在當前功能變數名稱內自動發送 cookie,必須提供這個選項 // 將arr對象序列化成json字元串, 向服務端傳入json數據 body: JSON.stringify(arr) }).then(res => { res.json().then( data => { // 請求返回數據 console.log(data) }) });
ajax
AJAX 是非同步的 JavaScript 和 XML。簡單點說,就是使用 XMLHttpRequest
對象與伺服器通信。它可以使用 JSON,XML,HTML 和 text 文本等格式發送和接收數據。AJAX 最吸引人的就是它的“非同步”特性,也就是說它可以在不重新刷新頁面的情況下與伺服器通信,交換數據,或更新頁面。
let xhr = new XMLHttpRequest(); xhr.open(method, url , sync) xhr.onreadystatechange = ()=> { if (readystate == 4) { // 說明請求已經完成 if (xhr.status>=200 && xhr.status < 300 || xhr.status == 304) { console.log(xhr.responseText) } else { // request was unsuccessful } } }
xhr.send(data)
稍微包裝一下:
let Ajax = { get: function(url,fn){ let xhr = new XMLHttpRequest(); xhr.open('GET',url,false); xhr.onreadystatechange=function(){ // readyState==4說明請求已經完成 if(xhr.readyState==4){ if( xhr.status>=200 && xhr.status < 300 || xhr.status==304){ console.log(xhr.responseText); fn.call(xhr.responseText); } } } xhr.send(); }, // data應為'a=a1&b=b1'這種字元串格式,在jq里如果data為對象會自動將對象轉成這種字元串格式 post: function(url,data,fn){ let xhr=new XMLHttpRequest(); xhr.open('POST',url,false); // 添加http頭,發送信息至伺服器時內容編碼類型 xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); xhr.onreadystatechange=function(){ if (xhr.readyState==4){ if (xhr.status==200 || xhr.status==304){ // console.log(xhr.responseText); fn.call(xhr.responseText); } } } xhr.send(data); } }
ajax用法詳情:
1.open(method, url, async) 方法需要三個參數:
method:發送請求所使用的方法(GET或POST);與POST相比,GET更簡單也更快,並且在大部分情況下都能用;然而,在以下情況中,請使用POST請求:
①無法使用緩存文件(更新伺服器上的文件或資料庫)
②向伺服器發送大量數據(POST 沒有數據量限制)
③發送包含未知字元的用戶輸入時,POST 比 GET 更穩定也更可靠
url:規定伺服器端腳本的 URL(該文件可以是任何類型的文件,比如 .txt 和 .xml,或者伺服器腳本文件,比如 .asp 和 .php (在傳迴響應之前,能夠在伺服器上執行任務));
async:規定應當對請求進行非同步(true)或同步(false)處理;true是在等待伺服器響應時執行其他腳本,當響應就緒後對響應進行處理;false是等待伺服器響應再執行。
2.send() 方法可將請求送往伺服器。
3.onreadystatechange:存有處理伺服器響應的函數,每當 readyState 改變時,onreadystatechange 函數就會被執行。
4.readyState:存有伺服器響應的狀態信息。
0: 請求未初始化(代理被創建,但尚未調用 open() 方法)
1: 伺服器連接已建立(open方法已經被調用)
2: 請求已接收(send方法已經被調用,並且頭部和狀態已經可獲得)
3: 請求處理中(下載中,responseText 屬性已經包含部分數據)
4: 請求已完成,且響應已就緒(下載操作已完成)
5.responseText:獲得字元串形式的響應數據。
6.setRequestHeader():POST傳數據時,用來添加 HTTP 頭,然後send(data),註意data格式;GET發送信息時直接加參數到url上就可以,比如url?a=a1&b=b1。
axios
Axios
是一個基於promise
的HTTP
庫,可以用在瀏覽器和 node.js
中。它本質也是對原生XMLHttpRequest
的封裝,只不過它是Promise的實現版本,符合最新的ES規範。
axios({ method: 'post', url: '/user/12345', data: { firstName: 'liu', lastName: 'weiqin' } }) .then(res => console.log(res)) .catch(err => console.log(err))
Vue2.0之後,尤雨溪大大推薦大家使用axios
來請求數據。
優點:
- 從瀏覽器中創建
XMLHttpRequests
- 從
node.js
創建http
請求 - 支持
Promise
API - 攔截請求和響應
- 轉換請求數據和響應數據
- 取消請求
- 自動轉換
JSON
數據 - 客戶端支持防禦
XSRF
缺點:
- 只持現代代瀏覽器
三、fetch請求中的跨域和攜帶Cookies問題
在有些請求中會遇到希望通過請求來訪問不同源的api,並且希望攜帶cookies。
解決跨域問題
fetch可以設置不同的模式使得請求有效. 模式可在fetch方法的第二個參數對象中定義.
fetch(url, {mode: 'cors'});
可以定義的模式如下:
same-origin:表示同源可以進行訪問,反之瀏覽器拒絕
cors: 表示同源和帶有cors響應頭的跨域可以請求成功,其他拒絕
cors-with-forced-preflight: 表示在發出請求前, 將執行preflight檢查.
no-cors: 表示跨域請求不帶cors響應頭場景,此時的相應類型為opaque,但是在opaque的返回類型中,我們幾乎不能查看到任何有價值的信息,比如不能查看response, status, url。
解決跨域攜帶cookies問題
為了讓瀏覽器發送包含憑據的請求(即使是跨域源),要將 credentials: 'include'
添加到傳遞給 fetch()
方法的 init
對象。
fetch('https://example.com', {
credentials: 'include'
});
解決fetch沒有超時時間
方案一
使用一個promise來封裝,通過setTimeout()來設置一個時間,如果超過該事件,就返回reject。
return new Promise((resolve, reject) => {
fetch(url, init)
.then(resolve)
.catch(reject);
setTimeout(reject, timeout);
})
}
在這裡,fetch會和setTimeout同時執行,因為fetch是非同步的,不會堵塞後面setTimeout的執行。
方案二
使用ES6中promise方法:
- Promise.race([promise1,promise2]) 傳入多個Promise對象,等待最快對象完成
- Promise.all([promise1,promise2]) 傳入多個Promise 對象,等待所有對象完成
let timeoutPromise = (timeout) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("我是 timeoutPromise,已經完成了");
}, timeout);
});
}
let requestPromise = (url) => {
return fetch(url);
};
Promise.race([timeoutPromise(1000), requestPromise("https://www.baidu.com")])
.then(resp => {
console.log(resp);
})
.catch(error => {
console.log(error);
});
如果需要取消請求,可以使用AbortController , 用於手動終止一個或多個DOM請求,通過該對象的AbortSignal註入的Fetch的請求中。