前端跨域請(qǐng)求原理及實(shí)踐

一、 跨域請(qǐng)求的含義

2.3 使用 標(biāo)簽原生實(shí)現(xiàn) JSONP

經(jīng)過上面的事件,你是不是覺得 JSONP 的實(shí)現(xiàn)和 Ajax 大同小異?

其實(shí),由于實(shí)現(xiàn)的原理不同,由 JSONP 實(shí)現(xiàn)的跨域調(diào)用不是通過 XmlHttpRequset 對(duì)象,而是通過 script 標(biāo)簽,所以在實(shí)現(xiàn)原理上,JSONP 和 Ajax 已經(jīng)一點(diǎn)關(guān)系都沒有了。看上去形式相似只是由于 jQuery 對(duì) JSONP 做了封裝和轉(zhuǎn)換。

比如在上面的例子中,我們假設(shè)要傳輸?shù)臄?shù)據(jù) data 格式如下:

{

name:"chiaki",

id": "3001"

}

那么數(shù)據(jù)是如何傳輸?shù)哪??HTTP 請(qǐng)求頭的第一行如下:

GET /ajax/deal?callback=jsonpCallback&name=chiaki&id=3001&_=1473164876032 HTTP/1.1

可見,即使形式上是用 POST 傳輸一個(gè) JSON 格式的數(shù)據(jù),其實(shí)發(fā)送請(qǐng)求時(shí)還是轉(zhuǎn)換成 GET 請(qǐng)求。

其實(shí)如果理解 JSONP 的原理的話就不難理解為什么只能使用 GET 請(qǐng)求方法了。由于是通過 script 標(biāo)簽進(jìn)行請(qǐng)求,所以上述傳輸過程根本上是以下的形式:

這樣從服務(wù)器返回的代碼就可以直接在這個(gè) script 標(biāo)簽中運(yùn)行了。下面我們自己實(shí)現(xiàn)一個(gè) JSONP:

服務(wù)器 3000請(qǐng)求頁面的 JavaScript 代碼中,只有回調(diào)函數(shù) jsonpCallback:

functionjsonpCallback(data){

console.log("jsonpCallback: "+data.name)

}

服務(wù)器 3000請(qǐng)求頁面還包含一個(gè) script 標(biāo)簽:

服務(wù)器 3001上對(duì)應(yīng)的處理函數(shù):

app.get('/jsonServerResponse',function(req,res){

varcb=req.query.jsonp

console.log(cb)

vardata='var data = {'+'name: $("#name").val() + " - server 3001 jsonp process",'+'id: $("#id").val() + " - server 3001 jsonp process"'+'};'

vardebug='console.log(data);'

varcallback='$("#submit").click(function() {'+data+cb+'(data);'+debug+'});'

res.send(callback)

res.end()

})

與上面一樣,我們?cè)谒@取的參數(shù)后面加上 “ – server 3001 jsonp process” 代表服務(wù)器對(duì)數(shù)據(jù)的操作。從代碼中我么可以看到,處理函數(shù)除了根據(jù)參數(shù)做相應(yīng)的處理,更多的也是進(jìn)行字符串的拼接。

最終的結(jié)果為:

2.4 JSONP 總結(jié)

至此,我們了解了 JSONP 的原理以及實(shí)現(xiàn)方式,它幫我們實(shí)現(xiàn)前端跨域請(qǐng)求,但是在實(shí)踐的過程中,我們還是可以發(fā)現(xiàn)它的不足:

只能使用 GET 方法發(fā)起請(qǐng)求,這是由于 script 標(biāo)簽自身的限制決定的。

不能很好的發(fā)現(xiàn)錯(cuò)誤,并進(jìn)行處理。與 Ajax 對(duì)比,由于不是通過 XmlHttpRequest 進(jìn)行傳輸,所以不能注冊(cè) success、 error 等事件監(jiān)聽函數(shù)。

三、 使用 CORS 實(shí)現(xiàn)跨域調(diào)用

3.1 什么是 CORS?

Cross-Origin Resource Sharing(CORS)跨域資源共享是一份瀏覽器技術(shù)的規(guī)范,提供了 Web 服務(wù)從不同域傳來沙盒腳本的方法,以避開瀏覽器的同源策略,是 JSONP 模式的現(xiàn)代版。與 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。用 CORS 可以讓網(wǎng)頁設(shè)計(jì)師用一般的 XMLHttpRequest,這種方式的錯(cuò)誤處理比 JSONP 要來的好。另一方面,JSONP 可以在不支持 CORS 的老舊瀏覽器上運(yùn)作?,F(xiàn)代的瀏覽器都支持 CORS。

3.2 CORS 的實(shí)現(xiàn)

還是以 服務(wù)器 3000 上的請(qǐng)求頁面向 服務(wù)器 3001 發(fā)送請(qǐng)求為例。

服務(wù)器 3000 上的請(qǐng)求頁面 JavaScript 不變,如下:

$(function(){

$("#submit").click(function(){

vardata={

name:$("#name").val(),

id:$("#id").val()

};

$.ajax({

type:'POST',

data:data,

url:'http://localhost:3001/cors',

dataType:'json',

cache:false,

timeout:5000,

success:function(data){

console.log(data)

},

error:function(jqXHR,textStatus,errorThrown){

console.log('error '+textStatus+' '+errorThrown);

}

});

});

});

服務(wù)器 3001上對(duì)應(yīng)的處理函數(shù):

app.post('/cors',function(req,res){

res.header("Access-Control-Allow-Origin","*");

res.header("Access-Control-Allow-Headers","X-Requested-With");

res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");

res.header("X-Powered-By",' 3.2.1')

res.header("Content-Type","application/json;charset=utf-8");

vardata={

name:req.body.name+' - server 3001 cors process',

id:req.body.id+' - server 3001 cors process'

}

console.log(data)

res.send(data)

res.end()

})

在服務(wù)器中對(duì)返回信息的請(qǐng)求頭進(jìn)行了設(shè)置。

最終的結(jié)果為:

3.3 CORS 中屬性的分析

Access-Control-Allow-Origin

The origin parameter specifies a URI that may access the resource. The browser must enforce this. For requests without credentials, the server may specify “*” as a wildcard, thereby allowing any origin to access the resource.

Access-Control-Allow-Methods

Specifies the method or methods allowed when accessing the resource. This is used in response to a preflight request. The conditions under which a request is preflighted are discussed above.

Access-Control-Allow-Headers

Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.

3.4 CORS 與 JSONP 的對(duì)比

CORS 除了 GET 方法外,也支持其它的 HTTP 請(qǐng)求方法如 POST、 PUT 等。

CORS 可以使用 XmlHttpRequest 進(jìn)行傳輸,所以它的錯(cuò)誤處理方式比 JSONP 好。

JSONP 可以在不支持 CORS 的老舊瀏覽器上運(yùn)作。

四、 一些其它的跨域調(diào)用方式

4.1 window.name

window對(duì)象有個(gè)name屬性,該屬性有個(gè)特征:即在一個(gè)窗口 (window) 的生命周期內(nèi),窗口載入的所有的頁面都是共享一個(gè) window.name 的,每個(gè)頁面對(duì) window.name 都有讀寫的權(quán)限,window.name 是持久存在一個(gè)窗口載入過的所有頁面中的,并不會(huì)因新頁面的載入而進(jìn)行重置。

4.2 window.postMessage()

這個(gè)方法是 HTML5 的一個(gè)新特性,可以用來向其他所有的 window 對(duì)象發(fā)送消息。需要注意的是我們必須要保證所有的腳本執(zhí)行完才發(fā)送 MessageEvent,如果在函數(shù)執(zhí)行的過程中調(diào)用了他,就會(huì)讓后面的函數(shù)超時(shí)無法執(zhí)行。

參考:https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在線閱讀 http://interview.poetries.top[http://interview.poetr...
    前端進(jìn)階之旅閱讀 115,521評(píng)論 24 450
  • 我在桃花下看夕陽 美麗而憂傷 我看著我的孩子在春天里奔跑 如我在你眼中的樣子 我感覺自己還沒有長(zhǎng)大 你卻在安然中慢...
    雪兒飛閱讀 294評(píng)論 0 0
  • 迷迷糊糊,渾渾噩噩過了一天,六級(jí)考試在懵懂中結(jié)束。 遇到20年的閨密,倔強(qiáng)的兩個(gè)人都選擇了沉默,就像另一個(gè)人告訴我...
    漓邇兒閱讀 254評(píng)論 0 0
  • 1、《1984》 喬治·奧威爾(著) 書摘 黨的一句口號(hào)說,誰控制過去就控制未來,控制現(xiàn)在就是控制過去。雖然從其性...
    我在樹下等你讀書閱讀 258評(píng)論 0 0
  • 七、韶山?jīng)_朝圣 8月28日吃過午飯,向韶山進(jìn)發(fā)。 從湘西的鳳凰古城到韶山,是這次行程中時(shí)間最長(zhǎng)的一段,大約要六個(gè)小...
    鐵嫵閱讀 401評(píng)論 35 26

友情鏈接更多精彩內(nèi)容