數(shù)據(jù)請求知多少
老鐵們都知道上網(wǎng)是通過瀏覽器發(fā)送HTTP請求券膀,接著服務器后收到請求,發(fā)送資源到瀏覽器谷扣,然后瀏覽器解析靜態(tài)資源(如html土全,css,js腳本)來展示給用戶会涎。(若對HTTP感興趣的裹匙,下期會出一個高級前端進階 ---http透析篇)
那前端開發(fā)人員在開發(fā)中,現(xiàn)有的幾種網(wǎng)絡請求數(shù)據(jù)的方法又有哪些呢末秃?它們又有什么不同呢概页?
下面,我們將聊聊數(shù)據(jù)請求這個話題练慕!let's go
數(shù)據(jù)請求之Ajax
ajax全稱是Asynchronous Javascript and XML (異步的JavaScript和XML)最早出現(xiàn)的發(fā)送后端請求數(shù)據(jù)的技術惰匙,一種在無需重新加載整個網(wǎng)頁的情況下,能夠更新部分網(wǎng)頁的技術铃将,屬于原生的js手段项鬼,核心的使用的是XMLHttpRequest對象,多個請求如果之間有先后順序的話劲阎, 就會出現(xiàn)煩人的callback hell绘盟。
數(shù)據(jù)請求之jQuery Ajax
jQuery Ajax是小胖子John Resig用jQuery對ajax進行底層的封裝。簡單的實現(xiàn)有:.post等悯仙。
$.ajax() 返回的是其內(nèi)部創(chuàng)建的XMLHttpRequest對象龄毡。一般不會使用這個這個函數(shù),除非需要更多的選擇锡垄。
數(shù)據(jù)請求之Axios
axios是需要安裝使用的沦零,支持瀏覽器客戶端,也支持nodejs端使用货岭。不是原生JS蠢终,是一個基于promise的HTTP庫。它的特性是:在瀏覽器中創(chuàng)建XMLHttpRequest茴她,在node.js中創(chuàng)建http請求,支持所有的promise的API程奠,攔截請求和響應丈牢,轉化請求數(shù)據(jù)和響應數(shù)據(jù),取消請求瞄沙,自動轉換JSON數(shù)據(jù)己沛,客戶端支持防御XSRF慌核。
什么是xsrf攻擊呢?
全稱是Cross Site Request Forgery申尼,跨站域請求偽造垮卓,是網(wǎng)絡攻擊的一種,關于網(wǎng)絡攻擊以后會出一篇詳細文章师幕。那這里axios是如何通過客戶端來防御xsrf呢粟按? 這里讓你的每個請求都帶一個從cookie中拿到的key,根據(jù)瀏覽器的同源策略霹粥,偽造的請求是拿不到你cookie的key的灭将,這樣,后臺就可以輕松辨別這個請求是否是用戶在假冒網(wǎng)站上的誤導輸入了后控,采用正確的策略進行回應庙曙。
數(shù)據(jù)請求之Fetch
Fetch是一個現(xiàn)代的概念,等同于XMLHttpRequest浩淘。提供了許多與XMLHttpRequest相同的功能捌朴,但被設計的更有擴展性和高效性,核心在于對HTTP接口的抽象张抄,包括Request,Response砂蔽,Headers,Body欣鳖,以及用于初始化異步請求的global fetch察皇。使fetch可以被使用到更多的應用場景中:無論是service worker,Cache API ,甚至是需要你自己在程序中生成響應的方式泽台。fetch也是基于promise設計的什荣。且代碼結構比ajax簡單多了,參數(shù)和jQuery ajax相似怀酷。但是稻爬,fetch不是對ajax的進行底層封裝,他就是原生的js
數(shù)據(jù)請求詳細說
由淺入深Ajax
通過使用ajax技術蜕依,通過在后臺與服務器進行少量的數(shù)據(jù)交換桅锄,就可以使頁面進行異步更新。這樣做的好處是样眠,可以在不用加載整個網(wǎng)頁的情況下友瘤,對網(wǎng)頁的某個部分進行更新。
Ajax的工作原理
瀏覽器端:發(fā)生某個事件檐束,創(chuàng)建XMLHttpRequest對象辫秧,發(fā)送HttpRequest ---> Internet ---> 在服務器端:處理HttpRequest 創(chuàng)建響應并將數(shù)據(jù)返回瀏覽器 ----> Internet ---> 在瀏覽器端: 使用js處理返回的數(shù)據(jù),顯示到頁面上
- 什么是XMLHttpRequest被丧?
XMLRequest讓發(fā)送HTTP請求變得非常的容易盟戏。只需要簡單的創(chuàng)建一個本實例對象绪妹,打開一個url,然后發(fā)送這個請求柿究。當傳輸完畢后邮旷,結果的HTTP狀態(tài),以及返回的響應內(nèi)容也可以從請求對象中獲取蝇摸。實例代碼:
function reqListener() {
console.log(this.responseText);
}
let oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener); //傳輸完畢婶肩,加載的數(shù)據(jù)保存在response中 reqListener是回調(diào)函數(shù)
oReq.open('GET','http://www.example.org/example.txt',true); //第三個參數(shù) true 意味著是異步請求
oReq.send();
- 請求類型
通過XMLHttpRequest生成的請求可以有兩種方式來獲取數(shù)據(jù),異步模式和同步模式探入。請求的類型由上述的實例代碼中的open() 方法的第三個參數(shù)async的值來決定的狡孔。如果該參數(shù)是false的話,則該XMLHttpRequest請求以同步模式進行蜂嗽,否則該過程將以異步模式完成苗膝。(在部分新版本的瀏覽器中,主線程上的同步請求已經(jīng)被放棄了)
- 處理響應
w3c規(guī)范定義了XMLHttpRequest對象的幾種類型的響應屬性植旧。這些屬性告訴客戶端關于XMLHttpRequest返回狀態(tài)的重要信息辱揭。一些處理非文本返回類型的用例可能包含一些下面章節(jié)中描述的操作和分析。
分析操作responseXML屬性:
它是一個只讀值病附,它返回一個包含請求檢索的HTML或XML的Document
问窃,如果請求未成功,尚未發(fā)送完沪,或者檢索的數(shù)據(jù)無法正確解析為 XML 或 HTML域庇,則為 null。默認是當作“text / xml” 來解析覆积。當 responseType
設置為 “document” 并且請求已異步執(zhí)行時听皿,響應將被當作 “text / html” 來解析。responseXML
對于任何其他類型的數(shù)據(jù)以及 data:
URLs 為 null宽档。
如果使用XMLHttpRequest來獲得一個遠程的XML文檔的內(nèi)容尉姨,responseXML屬性將會是一個由XML文檔解析而來的DOM對象,這很難被操作和分析吗冤。以下是五種主要的分析XML文檔的方式:
1又厉,使用XPath定位到文檔的指定部分。
2椎瘟,手工的解析和序列化XML為字符串或對象覆致。
3,使用XMLSerializer把DOM樹序列化成字符串或文件肺蔚。
4篷朵,如果預先知道XML文檔的內(nèi)容,你可以使用RegExp。如果你用RegExp掃描時受到換行符的影響声旺,你有可能想要刪除所有的換行符。然而段只,這種方法是“最后手段”腮猖,因為如果XML代碼發(fā)生了輕微的變化,該方法將可能失敗赞枕。
解析和操作包含HTML文檔的responseText屬性:
如果使用XMLHttpRequest從服務端獲取到一個HTML頁面澈缺,則所有HTML標記會以字符串的形式存放在responseText屬性里,這樣就使得操作和解析這些HTML標記變得非常的困難炕婶。解析這些標記主要會有以下的三種方式:
1姐赡,XMLHttpRequestresponseXML屬性
2,將內(nèi)容通過fragment.body.innerHTML注入到一個文檔片段中柠掂,并遍歷DOM中的片段项滑。
3,如果預先知道html文檔的內(nèi)容涯贞,可以使用RegExp枪狂。如果你用RegExp掃描時受到換行符的影響,你有可能想要刪除所有的換行符宋渔。然而州疾,這種方法是“最后手段”,因為如果HTML代碼發(fā)生了輕微的變化皇拣,該方法將可能失敗严蓖。
- 處理二進制數(shù)據(jù)
有時通過XMLHttpRequest也可以發(fā)送和接受二進制內(nèi)容,有很多方法可以強制使用XMLHttpRequest發(fā)送二進制數(shù)據(jù)氧急,利用XMLHttpRequest.overrideMimeType()方法是一個解決方案颗胡,雖然它并不是一個標準方法。
let oReq = new XMLHttpRequest();
oReq.open("GET",url,true);
oReq.overrideMimeType("text/plain;")
在XMLHttpRequest Level2 規(guī)范中新加入了responseType屬性态蒂,使用二進制通信變得更加容易和便捷杭措。
let oReq = new XMLHttpRequest();
oReq.onload = function(e) {
let arraybuffer = oReq.response; //not responseText
}
oReq.open("GET",url,true)
oReq.responseType = "arraybuffer" //在send之前修改數(shù)據(jù)類型 變?yōu)槎M制類型
oReq.send()
- 事件監(jiān)測
XMLHttpRequest 提供了各種在請求被處理期間發(fā)生的事件以供監(jiān)聽(如定期進度通知,錯誤處理等)
支持DOM的progress事件 監(jiān)測于XMLHttpRequest傳輸钾恢,遵循web API 進度事件規(guī)范:這些事件實現(xiàn)了ProgressEvent接口手素。
- 提交表單和上傳文件
XMLHttpRequest的實例有兩種方式來提交表單和上傳文件:
1, 使用Ajax
2,使用FormData API
使用formdata api 是最簡單最快捷的瘩蚪,但是被收集的數(shù)據(jù)無法使用JSON.stringify() 轉換為一個JSON字符串泉懦。
第一種方式是最復雜的但是是最靈活的和最強大的。
由淺入深 jQuery Ajax
實例:
$.ajax({
url: "/api/getWeather",
data: {
zipcode: 97201
},
success: function(result) {
$("#weather-temp").html("<h1>"+result+"</h1>")
}
})
第一個的Ajax指的是XMLHttpRequest(xhr)疹瘦,最早出現(xiàn)的發(fā)送后端請求崩哩,隸屬于原始的js,核心使用的是XMLHttpRequest對象,多個請求之間如果有先后關系的話邓嘹,會有callback hell 出現(xiàn)酣栈。
jQuery Ajax的出現(xiàn)是對原生xhr的封裝,除此之外還增添了對JSONP(向后端發(fā)送一個請求汹押,得到的是一個函數(shù)的調(diào)用矿筝,在前端頁面上掛載同名函數(shù))的支持,jQuery ajax的出現(xiàn)棚贾,很大程度上解決了數(shù)據(jù)請求的普遍問題窖维,但是隨著現(xiàn)行的react,vue等框架的興起和大批的使用妙痹,以及ES規(guī)范的完善铸史,更多API的更新,使jQuery ajax 開始暴露出弱點:
1怯伊,本身是怎對MVC的編程琳轿,不符合現(xiàn)在的MVVM框架的使用,配置和調(diào)用方式非常的混亂震贵,基于事件的異步模型不太友好利赋。
2,基于原生的XHR開發(fā)猩系,XHR自己的架構都不清晰媚送,也有了Fetch的替代方案的提出。
3寇甸,jQuery整個項目太大塘偎,單純使用ajax要引入整個jQuery,這樣非常不明智拿霉。
默認的情況下吟秩,ajax請求使用的GET方法。如果要使用POST方法绽淘,可以設定Type參數(shù)值涵防。這個選項也會影響data選項中的內(nèi)容如何發(fā)送到服務器(是在地址欄中還是請求體中)。
data選項既可以是一個查詢字符串沪铭,比如key1=value1&key2=value2,也可以是一個映射壮池,比如{ key1: 'value1',key2: 'value2' }。如果使用了映射的形式杀怠,則數(shù)據(jù)再被發(fā)送會被轉換成查詢字符串椰憋。這個處理方式可以通過processData選項為false來回避。若是要發(fā)送一個XML對象給服務器時赔退,這種并不合理橙依。我們也應當改變contentType選項的值证舟,用其他合適的MIME類型來取代默認的application/x-www-form-urlencoded。
var list = {}
$.ajax({
//請求方式
type: "POST",
//請求類型
contentType: "application/json;charset=UTF-8",
//請求地址
url: "http://127.0.0.1/xxx/",
//數(shù)據(jù),json字符串.
data: JSON.stringify(list),
//請求成功
success: function(result) {
console.log(rusult)
},
error: function(e) {
console.log(e.status);
console.log(e.responseText)
}
})
方法 | 描述 |
---|---|
$.ajax() | 執(zhí)行異步AJAX請求 |
$.ajaxPrefilter() | 每個請求發(fā)送之前且被$.ajax()處理之前窗骑,處理自定義Aajx選項或修改已存在選項 |
$.ajaxSetup() | 為將來的AJAX請求設置默認值 |
$.get() | 使用AJAX的HTTP GET請求從服務器加載數(shù)據(jù) |
$.getJSON() | 使用AJAX的HTTP GET 請求從服務器加載JSON編碼的數(shù)據(jù) |
$.getScript() | 使用AJAX的HTTP GET 請求從服務器加載并執(zhí)行JavaScript |
$.param() | 創(chuàng)建數(shù)組或對象的序列化表示形式(可用于AJAX請求的URL查詢字符串) |
$.post() | 使用AJAX的HTTP POST請求 |
ajaxComplete() | 規(guī)定AJAX請求完成時運行的函數(shù) |
ajaxError() | 規(guī)定AJAX請求失敗時運行的函數(shù) |
ajaxSend() | 規(guī)定AJAX請求發(fā)送之前時運行的函數(shù) |
ajaxStart() | 規(guī)定第一個AJAX請求發(fā)送之前運行的函數(shù) |
ajaxStop() | 規(guī)定所有的AJAX請求完成時運行的函數(shù) |
ajaxSuccess() | 規(guī)定AJAX請求成功時運行的函數(shù) |
load() | 從服務器加載數(shù)據(jù)女责,并把返回的數(shù)據(jù)放置到指定的元素中 |
serialize() | 編碼表單元素集為字符串以便提交 |
由淺入深Axios
實例:
//get 請求
axios.get('/user?ID=12345')
.then(function(response) {
console.log(response)
})
.catch(function(error) {
console.log(error)
})
//另一種寫法
axios.get('/user',{
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response)
})
.catch(function (error) {
console.log(error)
})
//post 請求
axios.post('/users',{
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function(response) {
console.log(response)
})
.catch(function(error) {
console.log(error)
})
// 執(zhí)行多個并發(fā)請求
function getUserAccount() {
return axios.get('/user/1234')
}
function getUserPermissions() {
return axios.get('/user/1234/permissions')
}
axios.all([getUserAccount(),getUserPermissions()])
.then(axios.spread(function (acct,perms) {
//請求都執(zhí)行完畢后
}))
在知多少中,我們已經(jīng)提到慧域,Axios本質(zhì)上是對原生XHR的封裝鲤竹,只不過是通過Promise的實現(xiàn)版本,可以用在瀏覽器端和node.js中昔榴,符合最新的ES規(guī)范。
用axios創(chuàng)建請求的時候可以用的配置選項碘橘,只有url是必需的互订。如果沒有指定的method,請求將默認使用get方法痘拆。
axios既提供了并發(fā)的封裝仰禽,體積也較小。也沒有fetch的一些獲取問題纺蛆。目前來看吐葵,這也是尤玉溪在vue中推崇axios的原因。
由淺入深Fetch
Fetch是一個現(xiàn)代的概念桥氏,等同于XMLHttpRequest温峭。提供了許多與XMLHttpRequest相同的功能,但被設計的更有擴展性和高效性.
核心在于對HTTP接口的抽象字支,包括Request,Response凤藏,Headers,Body堕伪,以及用于初始化異步請求的global fetch揖庄。
也提供了一個全局的fetch() 方法,該方法提供了一種簡單欠雌,合理的方式來跨網(wǎng)絡異步獲取資源蹄梢。
請注意,fetch規(guī)范和jQuery ajax() 有兩種方式的不同:
- 當接收的一個錯誤的HTTP狀態(tài)碼(404)富俄,從fetch() 返回的是Promise 不會被標記為reject禁炒,即便該HTTP響應的狀態(tài)碼是500。它會將promise狀態(tài)標記為resolve(但是會將resolve的返回值得ok屬性設置為false)蛙酪,僅當網(wǎng)絡故障或請求被阻止時齐苛,才會標記為reject。
- 默認情況下桂塞,fetch不會從服務端發(fā)送或接收任何cookies凹蜂,如果站點依賴于用戶session,則會導致未經(jīng)認證的請求(要發(fā)送cookies,必須設置credentials選項)
實例:
fetch('http://example.com/....json')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson)
})
這里我們可以通過網(wǎng)絡獲取一個JSON文件并將其打印到控制臺。最簡單的用法是只提供一個參數(shù)用來指明想fetch() 到的資源路徑玛痊,然后返回一個包含響應結果的promise(一個Response對象)
當然她只是一個HTTP響應汰瘫,不是真正的json。為了獲取JSON的內(nèi)容擂煞,我們需要使用json() 方法(在Bodymixin中定義混弥,被 Request和Response對象實現(xiàn))
fetch() 接受第二個可選參數(shù),一個可以控制不同配置的init對象:
function postData(url,data) {
return fetch(url,{
body: JSON.stringify(data),
cache: 'no-cache',
credentials: 'same-origin', //include
headers: {
'user-agent': 'Mozilla/4.0 MDN Example',
'content-type': 'application/json'
},
method: 'POST', // GET POST DELETE PUT
mode: 'cors', // no-cors cors same-origin
redirect: 'follow',
referrer: 'no-referrer',
})
.then(response=>response.json()) //轉化為json
}
postData('http://example.com/answer',{answer: 42})
.then(data=>console.log(data))
.catch(error=>console.error(error))
fetch的優(yōu)點:
1对省,語法更加簡潔
2蝗拿,基于標準Promise實現(xiàn),支持async/await
3蒿涎,更加底層哀托,使用的API更加豐富(request,response)
4劳秋,脫離了xhr仓手,是ES規(guī)范里新的實現(xiàn)方式
5,跨域的請求處理
在設置了跨域頭或借助了JSONP的前提下玻淑,瀏覽器的請求是可能隨便跨域嗽冒,但是,fetch中可以設置mode來進行是否跨域补履。
fetch的mode
配置項有3個值添坊,如下:
same-origin
:該模式是不允許跨域的,它需要遵守同源策略干像,否則瀏覽器會返回一個error告知不能跨域帅腌;其對應的response type為basic
。意味值請求必須是同源下麻汰。cors
: 該模式支持跨域請求速客,顧名思義它是以CORS的形式跨域;當然該模式也可以同域請求不需要后端額外的CORS支持五鲫;其對應的response type為cors
溺职。 通過cors方式跨域,后臺配合位喂。no-cors
: 該模式用于跨域請求但是服務器不帶CORS響應頭浪耘,也就是服務端不支持CORS;這也是fetch的特殊跨域請求方式塑崖;其對應的response type為opaque
七冲。
針對跨域請求,cors模式是常見跨域請求實現(xiàn)规婆,但是fetch自帶的no-cors
跨域請求模式則較為陌生澜躺,該模式有一個比較明顯的特點:
該模式允許瀏覽器發(fā)送本次跨域請求蝉稳,但是不能訪問響應返回的內(nèi)容,這也是其response type為opaque透明的原因掘鄙。
這與<img/>
發(fā)送的請求類似(通過src請求到一個資源耘戚,也可以通過fetch來請求image),該模式不能訪問響應的內(nèi)容信息操漠;但是它可以被其他APIs進行處理,例如ServiceWorker浊伙。另外,該模式返回的repsonse可以在Cache API中被存儲起來以便后續(xù)的對它的使用嚣鄙,這點對script部服、css和圖片的CDN資源是非常合適的。
總得來說奉芦,fetch在前端跨域的處理上功能非常強大赵抢,原生xhr可望不可及烦却。
參考資料: axios官網(wǎng) / fetch mdn
參考公眾號文章:幾種數(shù)據(jù)請求的介紹,區(qū)別及優(yōu)缺點 --- 全棧者