本文講解瀏覽器請求的發展歷程,從傳統web應用到ajax,再到jquery,直到目前最為流行的axios。(重點詳細講,沒用過的寫個思想)
一、傳統web應用
傳統的網頁(不使用 AJAX)如果需要更新內容,必需過載整個網頁。過程是使用者在客戶端觸發HTTP請求,伺服器處理請求並返回新的HTHL頁到客戶端,客戶端再重新讀取整個頁面。即使很小的互動,也要完成上述過程,導致浪費頻寬且互動響應很慢。
在這個背景下,出現了可以更新部分網頁資料的Ajax技術。
二、Ajax
1. 概念
AJAX即 Asynchronous JavaScript and XML。它不是新的程式語言,而是在不重新載入整個頁面的情況下,與服務端交換資料並更新部分網頁的技術。
2. 原理
Ajax 的工作原理相當於在使用者和伺服器之間加了—箇中間層,使使用者操作與伺服器響應非同步化,並且確定需要從伺服器讀取新資料時再由Ajax引擎代為向伺服器提交請求,像—些資料驗證和資料處理等都交給Ajax引擎自己來做,並不提交給服務端,提升效能。
3. 簡單示例
Ajax 核心由 XMLHTTPRequest、JavaScript、DOM 物件組成,通過XmlHttpRequest物件來向伺服器發非同步請求,從伺服器獲得資料,然後用 JavaScript 來操作 DOM 而更新頁面。
const xmlHttp = new XMLHttpRequest()
// 傳送請求
xmlHttp.open('GET', 'text1.txt', true) // open(method,url,async)
xmlHttp.send()
// 響應處理
xmlHttp.onreadystatechange = function () {
// 請求已完成,且響應就緒
if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
document.getElementById('div1').innerHTML = xmlHttp.responsText
}
}
複製程式碼
4. XMLHttpRequest物件
- readyState:存有 XMLHttpRequest 的狀態。從 0 到 4 發生變化。改變時觸發onreadystatechange
- 0: 請求未初始化
- 1: 伺服器連線已建立
- 2: 請求已接收
- 3: 請求處理中
- 4: 請求已完成,且響應已就緒
- status: 伺服器的HTTP狀態碼
- 200: "OK"
- 404: 未找到頁面
- ...
5. 優缺點
-
優點:
- 無重新整理更新資料,使用者體驗提高
- 按需取資料,節約空間和頻寬
- 部分工作轉嫁到客戶端,減輕伺服器負擔
- 基於標準被支援
-
缺點:
- 客戶端變的複雜,容易出錯
- 移動裝置支援較差
- 安全問題
三、Jquery
1. 背景
因為不同的瀏覽器對 AJAX 的實現並不相同,所以編寫統一的 AJAX 程式碼相對複雜。例如IE5、IE6沒有XMLHttpRequest物件,而是ActiveXObject。
Jqury 庫對 AJAX 進行了封裝,使得我們可以通過更為簡單統一的方式實現 AJAX 功能,同時能夠把這些外部資料直接載入網頁的被選元素中。
2. 主要 API 介紹
- $(selector).load(URL, data, callback): 從服務端獲取獲取並將資料載入到DOM元素中
- $.get(URL,callback) : 使用 GET 方法從服務端獲取資料
- $.post( url [, data ] [, success ] [, dataType ] ) : 通過 HTTP POST 請求從伺服器上請求資料。
- api詳情
四、Fetch
1. Why fetch
傳統ajax(指的是 XmlHttpRequest,即XHR)已經逐漸被Fetch替代。原因:
- Fetch語法簡單,更加語義化, 並能方便的配置請求物件。
- 不需要引入jquery,且移動端支援較好
2. 簡單示例
fetch(url).then(function(response) {
return response.json();
}).then(function(data) {
console.log(data);
}).catch(function(e) {
console.log("Oops, error");
});
// 使用 ES6 的 箭頭函式 後:
fetch(url).then(response => response.json())
.then(data => console.log(data))
.catch(e => console.log("Oops, error", e))
複製程式碼
3. polyfill: whatwg-fetch
fetch的原生支援並不好,通過引入polyfill來支援主流瀏覽器。實質是對於不支援 fetch api 的瀏覽器,使用 XMLHttpRequest 模擬實現 fetch api。
-
關鍵原始碼:
if (self.fetch) { return } ... self.fetch = function(input, init) { return new Promise(function(resolve, reject) { var request = new Request(input, init) var xhr = new XMLHttpRequest() xhr.onload = function() {...} } } 複製程式碼
-
plato((專案採用的vue腳手架)引入方法:
// src/polyfills/index import 'whatwg-fetch' // webpack.config.bable.js entry: { app: [ paths.src('polyfills/index.js'), // 載入 polyfills paths.src('index.js')] // 載入入口 } 複製程式碼
-
和Jquery.ajax()的區別
-
伺服器返回 404,500 錯誤碼時並不會reject,只有網路錯誤或者其他原因導致請求不能完成時,fetch 才會被 reject。為了保證reject HTTP錯誤狀態,可做如下處理:eg:所有非2xx的錯誤碼都丟擲錯誤異常。 (----- 不好用,有時候需要做處理)
function checkStatus(response) { if (response.status >= 200 && response.status < 300) { return response } else { var error = new Error(response.statusText) error.response = response throw error } } function parseJSON(response) { return response.json() } fetch('/users') .then(checkStatus) .then(parseJSON) .then(function(data) { console.log('request succeeded with JSON response', data) }).catch(function(error) { console.log('request failed', error) }) 複製程式碼
-
plato(專案採用的vue腳手架)實現建request.js
const body = await getBody(res) if (res.status >= 200 && res.status < 400) { return body } else { throw body } async function getBody (res) { const type = res.headers.get('Content-Type') if (type && type.indexOf('json') !== -1) { return await res.json() } const body = await res.text() try { return JSON.parse(body) } catch (error) { return { body } } } 複製程式碼
-
-
Fetch 請求預設是不帶 cookie 的,而且也不接收cookie。
-
傳送cookie
- 不跨域:fetch(url, {credentials: 'same-origin'})
- CORS 跨域請求:fetch(url, {credentials: 'include'})
-
接收cookie
同XHR相同, 從服務端返回的響應頭Set-Cookie
是一個被禁的欄位,所以不能通過response.headers.get()
來獲取。獲取cookie應該是瀏覽器的職責,通過document.cookie
來實現。
-
4. fetch() 詳解
- 語法: Promise fetch(input[, init])
- 引數
- input:定義要獲取的資源
USV字串
,包含要獲取資源的URL- Request物件
- init: 一個配置項物件,包括所有對請求的設定。可選的引數有:
- method
- headers
- body
- mode
- credientials
- cache
- ...
- input:定義要獲取的資源
- 返回值: 一個 Promise,resolve 時回傳 Response 物件。
五、Axios
基於Promise的HTTP庫,用於瀏覽器端和Node.js端, 底層實現也是封裝XMLHttpRequest。
-
Why axios:
- 支援兩端:browser, nodejs
- 支援攔截器
- 支援json資料自動轉換
- 基於promise,使用簡單
- 體積小
- fetch 實現偏底層,通常需要封裝後使用,axios可直接用
-
特點
- 瀏覽器端:make XMLHttpRequest
- Nodejs:make http request
- 支援promise api
- 支援請求 intercept、響應intercept
- 自動轉換JSON資料
參考: