前端網(wǎng)絡(luò)請求的方式主要有 Ajax 职抡,jQuery封裝的 Ajax膏孟,fetch眯分,axios、request 等開源庫等骆莹。
這里插一下http response status
颗搂,指示一個 http 請求是否成功完成担猛,具體分為五類:
(1) informational responses幕垦,1XX丢氢,臨時回應(yīng),表示客戶端請繼續(xù):
100 Continue: 代表目前一切正常先改,客戶端應(yīng)該繼續(xù)等待請求完成疚察,或者直接忽略如果請求已經(jīng)完成。
101 Switching Protocol: 對客戶端發(fā)送的 Upgrade請求頭的回應(yīng)仇奶,請求者已要求服務(wù)器切換協(xié)議貌嫡,服務(wù)器已確認(rèn)并準(zhǔn)備切換。
102 Processing: 代表服務(wù)器已經(jīng)收到請求并正在處理该溯,不過此時仍沒有響應(yīng)返回岛抄。
103 Early Hints: 主要用于 Link 頭以允許客戶端開始預(yù)加載資源,而此時服務(wù)器仍在準(zhǔn)備一個響應(yīng)狈茉。
(2) successful responses:
200 OK: 請求成功夫椭,但具體含義依請求方法而異,具體參考MDN
201 Created: 請求成功氯庆,并且因該請求而生成了新的資源蹭秋,通常是由于發(fā)送了 POST 或者 PUT 請求。
202 Accepted: 請求已被收到堤撵,但是沒有據(jù)此進(jìn)行進(jìn)一步操作仁讨,這表示無法返回一個異步響應(yīng)來代表請求處理的結(jié)果,這通常出現(xiàn)在另一個進(jìn)程或者服務(wù)器處理請求或者批處理中实昨。
203 Non-Authoritative Information: 非權(quán)威性信息洞豁,表示返回的元信息并非源于目標(biāo)服務(wù)器,而來自本地或者第三方副本荒给。
204 No Content: 對于請求沒有可返回的內(nèi)容族跛,即沒有新文檔,瀏覽器應(yīng)該繼續(xù)顯示原來的文檔锐墙。不過返回的響應(yīng)頭可能有用礁哄,客戶端可以據(jù)此更新對應(yīng)資源的緩存頭。
205 Reset Content:沒有新的內(nèi)容溪北,但瀏覽器應(yīng)該重置它所顯示的內(nèi)容桐绒。用來強(qiáng)制瀏覽器清除表單輸入內(nèi)容穿剖。
206 Partial Content: 因為客戶端發(fā)送了一個帶有Range頭的請求濒持,而Ranger頭用于將下載分為多個流。
還有207纹烹、208蚀乔、226自己查資料吧烁竭;
(3) redirects,3xx吉挣,表示請求的目標(biāo)有變化派撕,希望客戶端進(jìn)一步處理婉弹。
300 Multiple Choice: 請求可以有多個響應(yīng),客戶端自己挑一個终吼。即客戶端請求的資源可以在多個位置找到镀赌,這些位置已經(jīng)在返回的文檔內(nèi)列出。如果服務(wù)器要提出優(yōu)先選擇际跪,則應(yīng)該在Location應(yīng)答頭指明商佛。
301 Moved Permanently: 這意味著被請求資源對應(yīng)的URI已被永久改變了,舊地址A上的資源已被永久移除了而不可訪問了姆打。在可通過 Location 響應(yīng)頭給出新地址的URL良姆。
302 Found:這意味著被請求資源對應(yīng)的URI已被暫時改變了,舊地址A的資源仍可以訪問幔戏,重定向只是臨時地從地址A跳轉(zhuǎn)到地址B(詳細(xì)請看這篇文章).
(Note: 關(guān)于301歇盼、302狀態(tài)碼,參考這篇文章评抚,它們都表示重定向豹缀,即瀏覽器在拿到服務(wù)器返回的這個狀態(tài)碼后,會自動跳轉(zhuǎn)到一個新的URL(可從響應(yīng)的Location頭部中獲取慨代,用戶看到的效果就是他輸入的地址A變成了另一個地址B)邢笙,盡量使用301跳轉(zhuǎn))
303 See Other: 服務(wù)器返回該狀態(tài)碼指示客戶端通過GET方法使用另一個URI去獲取被請求的資源。
304 Not Modified: 出于緩存目的侍匙,告訴客戶端被請求的資源沒被修改氮惯,可以繼續(xù)使用對應(yīng)的緩存。即客戶端本地已經(jīng)有緩存的版本想暗,并且在 Request 中告訴了服務(wù)器妇汗,當(dāng)服務(wù)器通過 if-modified-since 或 e-tag 發(fā)現(xiàn)對應(yīng)資源沒更新時,就會返回一個不包含響應(yīng)體的304狀態(tài)说莫。 (這是在ajax請求中杨箭,唯一一個可以成功處理的重定向類狀態(tài)碼,其他3XX都不行)
307 Temporary Redirect: 語義上與 302一致储狭,只不過限制了客戶端不能改變使用的請求方法類型互婿,例如第一次請求使用的是 POST 方法,那么后續(xù)請求只能使用 POST 方法辽狈。
308 Permanent Redirect: 語義上與 301 一致慈参,不過限制了客戶端不能改變使用的請求方法類型。
(4) client errors:
400 Bad Request: 由于語法錯誤刮萌,服務(wù)器無法理解請求驮配。
401 Unauthorized: 語義上應(yīng)該是"unauthenticated",未經(jīng)驗證的,也有“未授權(quán)”的叫法壮锻,要求身份驗證琐旁。對于需要登錄的網(wǎng)頁,服務(wù)器可能返回該響應(yīng)(服務(wù)器:你要我提供服務(wù)躯保,先告訴我你是誰)。
403 Forbidden: 客戶端無權(quán)限獲取相應(yīng)內(nèi)容澎语,即未得到授權(quán)因此服務(wù)器拒絕返回相應(yīng)內(nèi)容途事。與401不同,服務(wù)器知道客戶端的身份擅羞,但不好意思尸变,人家就是不想給你提供服務(wù)。
404 Not Found: 這個太常見了减俏,服務(wù)器找不到被請求的資源(親召烂,我這邊沒有你要的東西哦)。不過服務(wù)器有時候也會用404代替403返回娃承,以此來向無權(quán)限的客戶端隱藏對應(yīng)資源的存在(我有奏夫,但騙你說沒有,哈哈)历筝。
405 Method Not Allowed: 服務(wù)器知道請求使用的方法酗昼,但不允許。例如禁止 Delete 方法防止刪除資源梳猪。不過 GET 和 HEAD 這兩個方法不可以被禁止麻削,即使用這兩個方法去請求資源,不應(yīng)該被返回 405.
406 Not Acceptable: 無法根據(jù)客戶端給定的規(guī)則找到內(nèi)容春弥。
407 Proxy Authentication Required: 與401類似呛哟,但是需要通過代理來完成驗證。
408 Request Timeout: 某些服務(wù)器會對空閑的連接(即沒有傳輸任務(wù)在進(jìn)行)發(fā)送該響應(yīng)匿沛,即使客戶端之前并未發(fā)送任何請求(即該響應(yīng)可以是服務(wù)器主動發(fā)送的)扫责,意味著服務(wù)器想要關(guān)閉該連接。
還有還多4XX逃呼,這里就不介紹了公给。
(5) servers eerors:
500 Internal Server Error: 服務(wù)器內(nèi)部錯誤。
501 Not Implemented: 請求使用的方法類型不被服務(wù)器所支持而無法處理蜘渣。不過服務(wù)器一般都支持 get 淌铐、head 方法。
502 Bad Gateway: 服務(wù)器作為網(wǎng)關(guān)或代理蔫缸,從上游服務(wù)器收到無效響應(yīng)腿准。
503 Service Unavailable: 服務(wù)器目前無法使用(由于超載或停機(jī)維護(hù)),通常只是暫時狀態(tài)。
504 Gateway Timeout: 網(wǎng)關(guān)超時吐葱,服務(wù)器作為網(wǎng)關(guān)或者代理街望,沒有及時從上游服務(wù)器收到請求。
505 HTTP Version Not Supported: 請求使用的HTTP版本不被服務(wù)器所支持弟跑。
1.原生 Ajax
Ajax: asynchoronous javascript and xml灾前,這種技術(shù)能夠向服務(wù)器請求數(shù)據(jù)而無須重新加載整個頁面,帶來更好的用戶體驗孟辑,關(guān)于ajax的超詳細(xì)介紹請移步這里
本人畫了下面這張示意圖
說明:
(1)發(fā)出請求(xhr.send())之前的語句都是同步執(zhí)行哎甲,從 send 方法內(nèi)部開始, 瀏覽器為將要發(fā)生的網(wǎng)絡(luò)請求創(chuàng)建新的http請求線程(這個線程獨立于js引擎線程)。網(wǎng)絡(luò)請求異步被發(fā)送出去后饲嗽,js 引擎并不會等待 ajax 發(fā)起的http請求收到結(jié)果, 而是直接順序往下執(zhí)行炭玫。
(2)當(dāng)ajax請求被服務(wù)器響應(yīng)并且收到 response 后,瀏覽器事件觸發(fā)線程捕獲到了ajax的相應(yīng)事件貌虾,并將 onreadystatechange (也可能是 onload 或者 onerror 等等)對應(yīng)的事件處理程序添加到 任務(wù)隊列 的末尾吞加。
(3)一次ajax請求, 并非所有的部分都是異步進(jìn)行的,例如 "readyState==1"的 onreadystatechange 回調(diào)以及 onloadstart 回調(diào)就是同步執(zhí)行的代碼尽狠。
xhr.send()剛開始執(zhí)行衔憨,onloadstart 回調(diào)方法就被觸發(fā)。
使用原生 ajax 的代碼如下:
let xhr=new XMLHttpRequest();
//狀態(tài)監(jiān)聽
xhr.onreadystatechange=function () {
console.log(xhr.readyState);
if(xhr.readyState===4){
if(xhr.status>=200 && xhr.status<300 || xhr.status==304){
console.log(xhr.responseText);
}
}
}
//異常處理
xhr.onerror=function(){
console.log("Ajax request failed.");
}
//設(shè)置相關(guān)事件回調(diào)方法
// onloadstart 在開始執(zhí)行 xhr.send()就會被觸發(fā)袄膏,屬于同步執(zhí)行巫财。
xhr.onloadstart=function(){
console.log('loadstart');
}
//超時處理
xhr.ontimeout=function(){
console.log("請求超時!")
}
//處理請求參數(shù)
postData={"name1":"value1","name2":"value2"};
postData=(function (value) {
let dataString="";
for(let key in value){
dataString+=key+"="+value[key]+"&";
}
return dataString;
})(postData);
xhr.open('get','https://www.qq.com',true);
//設(shè)置請求頭哩陕,要在 open 與 send 之間
// 推測是設(shè)置請求頭的時候平项,xhr需要已經(jīng)完成初始化
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');
//跨域攜帶cookie
xhr.withCredentials=true;
// 發(fā)出請求,之前的語句都是同步執(zhí)行
// 從send方法內(nèi)部開始, 瀏覽器為將要發(fā)生的網(wǎng)絡(luò)請求創(chuàng)建了新的http請求線程,
xhr.send(postData);
2.jQuery對 Ajax 的封裝
$.ajax({
dataType: 'json', // 設(shè)置返回值類型
contentType: 'application/json', // 設(shè)置參數(shù)類型
headers: {'Content-Type','application/json'},// 設(shè)置請求頭
xhrFields: { withCredentials: true }, // 跨域攜帶 cookie
data: JSON.stringify({a: [{b:1, a:1}]}), // 傳遞參數(shù)
error:function(xhr,status){ // 錯誤處理
console.log(xhr,status);
},
success: function (data,status) { // 獲取結(jié)果
console.log(data,status);
}
})
3.fetch
Fetch API是一個用用于訪問和操縱 HTTP 管道的強(qiáng)大的原生 API。
這種功能以前是使用 XMLHttpRequest 實現(xiàn)的悍及。Fetch 提供了一個更好的替代方法闽瓢,可以很容易地被其他技術(shù)使用,例如 Service Workers心赶。Fetch 還提供了單個邏輯位置來定義其他 HTTP 相關(guān)概念扣讼,例如 CORS 和 HTTP 的擴(kuò)展。
fetch是作為XMLHttpRequest的替代品出現(xiàn)的缨叫。
優(yōu)點:
(1)符合關(guān)注分離椭符,沒有將輸入、輸出和用事件來跟蹤的狀態(tài)混雜在一個對象里耻姥;
(2)更好更方便的寫法销钝;
(3)基于標(biāo)準(zhǔn) Promise 實現(xiàn),支持 async/await琐簇;
(4)更加底層蒸健,提供的API豐富(request, response);
(5)脫離了XHR,是ES規(guī)范里新的實現(xiàn)方式似忧。
使用fetch渣叛,你不需要再額外加載一個外部資源。但它還沒有被瀏覽器完全支持盯捌,所以仍然需要一個polyfill淳衙。
一個基本的fetch請求如下:
const options = {
method: "POST", // 請求參數(shù)
headers: { "Content-Type": "application/json"}, // 設(shè)置請求頭
body: JSON.stringify({name:'123'}), // 請求參數(shù)
credentials: "same-origin", // cookie 設(shè)置
mode: "cors", // 跨域
}
// fetch方法返回的是一個 promise
// fetch(input, init)
fetch('http://www.xxx.com', options)
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson); // 響應(yīng)數(shù)據(jù)
})
.catch(function(err){
console.log(err); // 異常處理
})
fetch polyfill 源碼
polyfill 主要對 fetch API 的 Headers, Request, Response, fetch 進(jìn)行了封裝。
(1) fetch
(a)構(gòu)造一個Promise對象并返回饺著;
(b)創(chuàng)建一個Request對象箫攀;
(c)創(chuàng)建一個XMLHttpRequest對象(注意 原生 fetch 并未使用 XHR 對象);
(d)取出Request對象中的請求url瓶籽,請求方發(fā)匠童,open一個xhr請求埂材,并將Request對象中存儲的headers取出賦給 xhr塑顺;
(e)xhr onload后取出response的status、headers俏险、body封裝Response對象严拒,調(diào)用resolve。
// fetch 方法的封裝
function fetch(input, init) {
return new Promise(function (resolve, reject) {
let request=new Request(input,init);
let xhr=new XMLHttpRequest();
xhr.open(request.method,request.url,true);
//響應(yīng)獲取完畢
xhr.onload=function () {
let options={
status:xhr.status,
statusText:xhr.statusText,
headers:parseHeaders(xhr.getAllResponseHeaders() || '')
}
options.url='responseURL' in xhr? xhr.responseURL:options.headers.get('X-Request-URL');
let body='response' in xhr? xhr.response: xhr.responseText;
resolve(new Response(body,options));
}
//異常處理
function abortXhr(){
xhr.abort();
}
// 1.請求失敗竖独,網(wǎng)絡(luò)故障或請求被阻止才觸發(fā)裤唠,
//而收到服務(wù)器異常狀態(tài)碼如404,500不會觸發(fā)
xhr.onerror=function(){
reject(new TypeError('Network request failed.'));
}
//2.請求超時
xhr.ontimeout=function(){
reject(new TypeError('請求超時'));
}
xhr.onabort=function(){
reject(new DOMException('Aborted','AbortError'));
}
//3.手動終止
if(request.signal){
request.signal.addEventListener('abort',abortXhr);
xhr.onreadystatechange=function () {
if(xhr.readyState===4){
request.signal.removeEventListener('abort',abortXhr);
}
}
}
// forEach 的具體實現(xiàn)在 Headers.prototype 中
request.headers.forEach(function (value, name) {
xhr.setRequestHeader(name,value);
});
xhr.send();
})
}
(2) Request
Request對象接收的兩個參數(shù)即fetch函數(shù)接收的兩個參數(shù),第一個參數(shù)可以直接傳遞url莹痢,也可以傳遞一個構(gòu)造好的request對象种蘸。第二個參數(shù)即控制不同配置的option對象。
// 2.Request對象封裝
function Request(input, options) {
options=options || {}
let body=options.body
if(input instanceof Request){
this.url=input.url
this.method=input.method
//...
}
else{
this.url=String(input)
}
this.credentials=options.credentials || this.credentials || 'same-origin'
if(options.headers || !this.headers){
this.headers=new Headers(options.headers)
}
this.method=normalizeMethod(options.method || this.method || 'GET')
this.mode=options.mode || this.mode || null
this.signal=options.signal || this.signal
this.referrer=null
//...
this._initBody(body)
}
(3) Headers
// 3.Headers 封裝
function Headers(headers) {
this.map={}
// (1)傳入的參數(shù)headers本身就是 Headers 的實例
if(headers instanceof Headers){
headers.forEach(function (value, name) {
this.append(name,value)
},this)
}
// (2)傳入的參數(shù)headers是數(shù)組類型(二維)
else if(Array.isArray(headers)){
headers.forEach(function (header) {
this.append(header[0],header[1])
},this)
}
// (3)傳入的參數(shù)headers是普通對象
else if(headers){
Object.getOwnPropertyNames(headers).forEach(function (name) {
this.append(name,headers[name])
})
}
}
在 Headers 中維護(hù)了一個map對象竞膳,構(gòu)造函數(shù)中可以傳入Headers對象航瞭、數(shù)組、普通對象類型的header坦辟,并將所有的值維護(hù)到map中刊侯。
fetch及上段代碼中都有 headers.forEach,這個 forEach 方法的具體實現(xiàn)如下:
Headers.prototype.forEach=function (callback, thisArg) {
for(let name in this.map){
if(this.map.hasOwnProperty(name)){
callback.call(thisArg,this.map[name],name,this)
}
}
}
可見header的遍歷即其內(nèi)部map的遍歷锉走。
另外Header還提供了append滨彻、delete、get挪蹭、set等方法亭饵,都是對其內(nèi)部的map對象進(jìn)行操作。
(4) Response
在 fetch中有對 Response 的操作:
xhr.onload=function(){
···
resolve(new Response(body,options))
}
function Response(bodyInit,options) {
options=options || {}
this.type='default'
this.status=options.status===undefined? 200 : options.status
this.ok=this.status>=200 && this.status<300
this.statusText='statusText' in options?options.statusText:'OK'
this.headers=new Headers(options.headers)
this.url=options.url || ''
// _initBody 是在 Body 函數(shù)中掛載到 Response.prototype 對象上的
this._initBody(bodyInit)
}
Body.call(Response.prototype)
可見在構(gòu)造函數(shù)中主要對options中的status梁厉、statusText冬骚、headers、url等分別做了處理并掛載到Response對象上。
構(gòu)造函數(shù)里面并沒有對responseText的明確處理只冻,最后交給了_initBody函數(shù)處理庇麦,而Response并沒有主動聲明_initBody屬性,代碼最后使用Response調(diào)用了Body函數(shù)喜德,實際上_initBody函數(shù)是通過Body函數(shù)掛載到Response身上的山橄,先來看看Body函數(shù):
function Body() {
this.bodyUsed=false;
// 這就是 Response 中的 _initBody
this._initBody=function (body) {
//具體代碼見后面
}
this.text=function () {
// _bodyText...
}
this.json=function () {
this.text().then(JSON.parse)
}
if(support.blob){
this.blob=function () {
//_bodyBlob...
}
}
if(support.formData){
this.formData=function () {
//_bodyFormData...
}
}
return this
}
Body函數(shù)中還為Response對象掛載了四個函數(shù),text舍悯、json航棱、blob、formData萌衬,這些函數(shù)中的操作就是將 _initBody 中得到的不同類型的返回值返回饮醇。
這也說明了,在fetch執(zhí)行完畢后秕豫,不能直接在response中獲取到返回值而必須調(diào)用text()朴艰、json()等函數(shù)才能獲取到返回值。
再來看看_initBody函數(shù)
function Body() {
this.bodyUsed=false;
// 這就是 Response 中的 _initBody
this._initBody=function (body) {
if(!body){
this._bodyText=''
}
else if(typeof body==='string'){
this._bodyText=body
}
else if(support.blob && Blob.prototype.isPrototypeOf(body)){
this._bodyBlob=body
}
else if(support.formData && FormData.prototype.isPrototypeOf(body)){
this._bodyFormData=body
}
// else if ...
else{
this._bodyText=body=Object.prototype.toString.call(body)
}
}
// ...
}
可見混移,_initBody函數(shù)根據(jù)xhr.response的類型(Blob祠墅、FormData、String...)歌径,為不同的參數(shù)進(jìn)行賦值毁嗦,這些參數(shù)在Body方法中得到不同的應(yīng)用.
這里還有一點需要說明:Response相關(guān)的幾個函數(shù)中都有類似下面的邏輯:
var rejected = consumed(this)
if (rejected) {
return rejected
}
function consumed(body) {
if (body.bodyUsed) {
return Promise.reject(new TypeError('Already read'))
}
body.bodyUsed = true
}
每次調(diào)用text()、json()等函數(shù)后會將bodyUsed變量變?yōu)閠rue回铛,用來標(biāo)識返回值已經(jīng)讀取過了狗准,下一次再讀取直接拋出TypeError('Already read')。這也遵循了原生fetch的原則:
因為 Responses 對象被設(shè)置為了 stream 的方式茵肃,所以它們只能被讀取一次腔长。
fetch 的缺點
(1)不能直接傳遞JavaScript對象作為參數(shù);
(2)需要自己判斷返回值類型免姿,并執(zhí)行響應(yīng)獲取返回值的方法饼酿;
(3)獲取返回值方法只能調(diào)用一次,不能多次調(diào)用胚膊;
(4)無法正常的捕獲異常(服務(wù)器返回 400故俐,500 錯誤碼時并不會 reject,而是會將 resolve 的返回值的 ok 屬性設(shè)置為 false紊婉;僅當(dāng)網(wǎng)絡(luò)故障時或請求被阻止時药版,才會標(biāo)記為 reject。)喻犁;
(5)老版瀏覽器不會默認(rèn)攜帶cookie槽片;
(6)不支持jsonp何缓;
(7)fetch不支持abort,不支持超時控制还栓,使用setTimeout及Promise.reject的實現(xiàn)的超時控制并不能阻止請求過程繼續(xù)在后臺運(yùn)行碌廓,造成了流量的浪費(fèi);
(8)fetch沒有辦法原生監(jiān)測請求的進(jìn)度剩盒,而XHR可以.
所以說半天谷婆, fetch并不是那么好用,偏底層辽聊,想要用的順手還要自己封裝纪挎,進(jìn)行諸如 請求參數(shù)處理、cookie攜帶跟匆、異常處理异袄、返回值處理等。
4.jsonp
fetch本身沒有提供對jsonp的支持玛臂,jsonp本身也不屬于一種非常好的解決跨域的方式烤蜕。不過呢,多了解一種方式也不是壞事垢揩。jsonp 本身很簡單玖绿,就是利用 script
標(biāo)簽的 src 屬性不受同源策略約束敛瓷,可進(jìn)行跨域請求叁巨,不過服務(wù)端需要進(jìn)行對應(yīng)的設(shè)置才行。
// 服務(wù)器端
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//數(shù)據(jù)
List<Student> studentList = getStudentList();
JSONArray jsonArray = JSONArray.fromObject(studentList);
String result = jsonArray.toString();
//前端傳過來的回調(diào)函數(shù)名稱
String callback = request.getParameter("callback");
//用回調(diào)函數(shù)名稱包裹返回數(shù)據(jù)呐籽,這樣锋勺,返回數(shù)據(jù)就作為回調(diào)函數(shù)的參數(shù)傳回去了
result = callback + "(" + result + ")";
response.getWriter().write(result);
}
上段代碼就是服務(wù)器端對 jsonp 請求的簡單處理(摘自)
下面就是對 jsonp 的封裝。
(function (window, document) {
"use strict";
let jsonp=function (url, data, callback) {
// 1.將傳入的data數(shù)據(jù)轉(zhuǎn)化為url字符串形式
// {id:1,name:'Jack'} => id=1&name=Jack
let dataString=url.indexOf('?')==-1? '?': '&';
for(let key in data){
dataString+=key+'='+data[key]+'&';
}
// 2.處理url中的回調(diào)函數(shù)
// cbFuncName 回調(diào)函數(shù)的名字 :my_json_cb_ 名字的前綴 + 隨機(jī)數(shù)(把小數(shù)點去掉)
let cbFuncName='my_json_cb_'+
Math.random().toString().replace('.','');
dataString+='callback='+cbFuncName;
// 3.創(chuàng)建一個 script 標(biāo)簽
let scriptEle=document.createElement('script');
scriptEle.src=url+dataString;
// 4.掛載回調(diào)函數(shù)(cbFuncName是變量狡蝶,不能直接作為回調(diào)函數(shù)名)
window[cbFuncName]=function (data) {
callback(data);
// 處理完回調(diào)函數(shù)的數(shù)據(jù)之后庶橱,刪除 jsonp 的 script 標(biāo)簽
document.body.removeChild(scriptEle);
}
document.body.appendChild(scriptEle);
}
// 通過給全局window對象添加$jsonp屬性,可在 此‘定義并立即調(diào)用匿名函數(shù)’執(zhí)行后贪惹,
// 在其他地方使用封裝好的jsonp
window.$jsonp=jsonp;
})(window,document)
//調(diào)用
let url='https://www.xxx.com';
let cb=function(data){console.log(data)}
window.$jsonp(url,null,cb);
5.axios
Vue大佬尤雨溪推薦大家用axios替換JQuery封裝的ajax.
axios 是一個基于Promise苏章,可用于瀏覽器和 nodejs 的 HTTP 客戶端,本質(zhì)上也是對原生XHR的封裝奏瞬,只不過它是Promise的實現(xiàn)版本枫绅,符合最新的ES規(guī)范,它本身具有以下特征:
1.從瀏覽器中創(chuàng)建 XMLHttpRequest
2.支持 Promise API
3.客戶端支持防止CSRF
4.提供了一些并發(fā)請求的接口(重要硼端,方便了很多的操作)
5.從 node.js 創(chuàng)建 http 請求
6.攔截請求和響應(yīng)
7.轉(zhuǎn)換請求和響應(yīng)數(shù)據(jù)
8.取消請求
9.自動轉(zhuǎn)換JSON數(shù)據(jù)
axios既提供了并發(fā)的封裝并淋,也沒有fetch的各種問題,而且體積也較小珍昨,你值得擁有县耽!
axios使用示例:
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
Reference
1.全面分析前端的網(wǎng)絡(luò)請求方式
2.ajax知識體系大梳理
3.ajax和axios句喷、fetch的區(qū)別
4.jsonp原理學(xué)習(xí)筆記