跨域解決方案

在工作過(guò)程中遇到了跨域問(wèn)題,參考了IBM一篇文章,寫(xiě)了一篇讀后感窟蓝,其實(shí)是按照自己的理解把原文幾乎翻譯了一遍,希望對(duì)大家有所幫助饱普,如果有問(wèn)題歡迎大家指正~原文地址: https://www.ibm.com/developerworks/library/wa-crossdomaincomm/

出于安全考慮运挫,瀏覽器有一些限制状共,在請(qǐng)求url資源的時(shí)候,域名谁帕、端口峡继、應(yīng)用協(xié)議,只要有一個(gè)和當(dāng)前頁(yè)面不同就認(rèn)為不同源匈挖,也就不允許訪問(wèn)碾牌,我們叫它sop(same origin policy)同源策略。栗子:現(xiàn)在有2個(gè)不同源的頁(yè)面A和頁(yè)面B儡循。

A頁(yè)面可以做的事:
1舶吗、從頁(yè)面B獲取css、js择膝、圖片文件
2誓琼、包含一個(gè)資源指向頁(yè)面B的iframe/frame元素
3、通過(guò)HTML元素的src屬性肴捉,向頁(yè)面B傳遞一些信息腹侣,比如ifram或img

A頁(yè)面不能做的事:
1、發(fā)起一個(gè)請(qǐng)求B頁(yè)面的ajax請(qǐng)求
2每庆、獲得或操作指向B頁(yè)面的iframe/frame的內(nèi)容

之所以增加這個(gè)限制筐带,就是防止在不同的網(wǎng)頁(yè)互相交換數(shù)據(jù)時(shí)今穿,保護(hù)用戶不受有害的攻擊缤灵。

有很多解決方案,例如:jsonp證明一個(gè)網(wǎng)頁(yè)可以動(dòng)態(tài)從其他的源加載腳本蓝晒,但是jsonp有2個(gè)主要的限制:1腮出、沒(méi)有錯(cuò)誤處理機(jī)制 2、必須用get方法芝薇,這就有了url長(zhǎng)度限制胚嘲,下面介紹幾個(gè)解決方案,每個(gè)方案各有優(yōu)缺點(diǎn)洛二,需要根據(jù)應(yīng)用場(chǎng)景選擇不同的解決方案馋劈。

Cross-subdomain solution###

原理圖:


頁(yè)面A和頁(yè)面B擁有同一個(gè)父域,可以通過(guò)設(shè)置document的domain屬性來(lái)通信晾嘶,栗子:A的域:www.xyy.com妓雾,B的域:chifan.xyy.com,這2個(gè)源有共同的父域xyy.com,就可以同時(shí)在A和B的html頁(yè)面中這樣設(shè)置:document.domain=xyy.com, 只能設(shè)置成父域垒迂,否則會(huì)報(bào)錯(cuò):Failed to set the 'domain' property on 'Document': 'corp.elong' is not a suffix of ‘127.0.0.1’。同一個(gè)父域下的2個(gè)子域通過(guò)設(shè)置共同的domain屬性可以互相通信机断,這種解決方案適用內(nèi)網(wǎng)應(yīng)用绣夺。

那么現(xiàn)在問(wèn)題來(lái)了欢揖,如果2個(gè)頁(yè)面沒(méi)有同一個(gè)父域怎么辦陶耍?就用下面一個(gè)稍微迂回的方法。

Cross-fragment technique###

原理圖:


在這個(gè)圖中如果A想和iframeB交互物臂,A首先會(huì)創(chuàng)建一個(gè)iframe,這個(gè)frame指向和B有著共同域名的“proxy C”,在C的url中
包含要發(fā)給B的所有參數(shù)产上、數(shù)據(jù)棵磷、frame標(biāo)識(shí)。上代碼:
function sendMsg(msg){
var frame = document.createElement(“iframe”);
var baseProxy = “http://www.otherapp.com/proxy.html”;
var request = {frameName:’otherApp’,data:msg};設(shè)置要交互的frame名稱
frame.src = baseProxy+”#”+encodeURI (dojo.toJson(request));//把要發(fā)送的msg添加到proxy的url里
frame.style.display=”none”;
document.body.appendChild(frame);
}
當(dāng)C加載后晋涣,會(huì)從url獲取A發(fā)來(lái)的數(shù)據(jù)仪媒,并且調(diào)用B的一個(gè)方法谢鹊,因?yàn)锽和C是同一個(gè)域名,所以C可以直接調(diào)用B的方法偎巢。
同理兼耀,B可以用統(tǒng)樣的方法給A返回?cái)?shù)據(jù)。
window.onLoad = function(){
var hash = window.location.hash;
if(hash && hash.length>1){
var request = hash.substring(1,hash.length);
var obj = dojo.fromJson(decodeURI (request));//從url的hash部分取出數(shù)據(jù)
var data = obj.data;
//process data
parent.frames[obj.frameName].getData(…);// 調(diào)用frameB的getData方法
}
}

URL.hash(fragment id) solution###

一個(gè)url由幾部分組成窍霞,見(jiàn)圖:



一般的拯坟,改變一個(gè)url會(huì)導(dǎo)致頁(yè)面的刷新,改變hash部分除外冷溃。(hash:我們俗稱的錨點(diǎn)梦裂,#后面跟著一個(gè)字符串,不會(huì)被當(dāng)做參數(shù)解析) 改變url的hash不會(huì)導(dǎo)致刷新頁(yè)面菠净,hash目前被廣泛應(yīng)用到
web 2.0當(dāng)部分刷新頁(yè)面時(shí)標(biāo)志每一步操作。在跨域交互時(shí)hash是一個(gè)很有用的特性毅往,不同源之間的文檔可以設(shè)置其他源
url的hash,盡管它們?cè)讷@取對(duì)方的hash時(shí)有限制攀唯,不同源之間可以通過(guò)hash發(fā)送消息洁桌。
栗子:
原理圖:


image.png

用幾段代碼說(shuō)明一下:
從A向B發(fā)送數(shù)據(jù):
function sendMsg(originURL, msg){
var data = {from:originURL, msg:msg};
var src = originURL + “#” + dojo.toJson(data); //把要發(fā)送的消息放到hash
document.getElementById('domainB').src=src;
}

B監(jiān)聽(tīng)從A過(guò)來(lái)的消息:
window.oldHash="";
checkMessage = function(){
var newHash = window.location.hash; //獲取當(dāng)前頁(yè)面url的hash
if(newHash.length > 1){
newHash = newHash.substring(1,newHash.length);
if(newHash != oldHash){ //如果檢測(cè)到和過(guò)去的hash不同另凌,就向A發(fā)送消息
oldHash = newHash;
var msgs = dojo.fromJson(newHash);
var origin = msgs.from;
var msg = msgs.msg;
sendMessage(origin, "Hello document A");
}
}
}
window.setInterval(checkMessage, 1000); //每隔1秒檢查一次hash
sendMessage = function(target, msg){
var hash = "msg="+ msg;
parent.location.href= target + “#” + hash;
}

就像jsonp一樣戒幔,這個(gè)方法也有長(zhǎng)度限制,但是它可以更好的進(jìn)行錯(cuò)誤處理工坊。如果要傳遞一些像?的保留字符敢订,
需要encode一下。
function sendMsg(originURL, msg){

var src = originURL + “#” + encodeURI (dojo.toJson(data));

}
jsonp為啥有長(zhǎng)度限制楚午?通過(guò)把不同源的url放在<script src=“other.origin.com:1001”></script>標(biāo)簽src的屬性矾柜,如果想要傳遞參數(shù),需要把所有要傳遞的參數(shù)放在get請(qǐng)求的url里把沼,src有長(zhǎng)度限制饮睬,因此傳遞的數(shù)據(jù)也有長(zhǎng)度限制篮奄。jsonp參考:https://web.archive.org/web/20160304044218/http://www.json-p.org/

OpenAjax implementation###

openAjax基于fragment id 和 cross-frame 實(shí)現(xiàn)跨域交互,簡(jiǎn)單來(lái)說(shuō)昼丑,openAjax統(tǒng)一管理不同源之間的數(shù)據(jù)交互夸赫,負(fù)責(zé)管理的模塊暫且叫成“master”,master有一個(gè)message的容器用來(lái)存message,每個(gè)源的iframe有自己的client side,client side有自己的container呼奢,當(dāng)iframe想要發(fā)消息時(shí),是它自己的container代替它向master的container發(fā)送消息握础,其他iframe通過(guò)自己的container監(jiān)聽(tīng)master的消息禀综,工作原理見(jiàn)下圖。


Window.name solution###

window的name屬性特性:當(dāng)頁(yè)面重新加載后name的值不變孤澎,window的name屬性可以被設(shè)置欠窒,利用這個(gè)特性實(shí)現(xiàn)跨域數(shù)據(jù)交互。原理圖:


image.png

當(dāng)A想要獲取B的內(nèi)容姐扮,A創(chuàng)建一個(gè)隱形的iframeB,指向B的url,當(dāng)獲取數(shù)據(jù)之后衣吠,在iframeB中把window.name設(shè)置成返回的數(shù)據(jù),這時(shí)候把頁(yè)面重定向到A的域名惊搏,A從window.name即可獲得返回的數(shù)據(jù)忧换。通過(guò)window.name傳遞數(shù)據(jù)的長(zhǎng)度比hash要多的多,大多數(shù)現(xiàn)代瀏覽器支持window.name傳輸16M+的數(shù)據(jù)酪耳。

H5中關(guān)于跨域傳輸?shù)男绿匦?##

window.postMessage(message, targetOrigin)實(shí)現(xiàn)安全跨域交互刹缝。當(dāng)調(diào)用這個(gè)函數(shù)時(shí),會(huì)分發(fā)一個(gè)消息事件言疗,如果window正在監(jiān)聽(tīng)這個(gè)消息事件颂砸,它可以獲得消息內(nèi)容并且知道發(fā)消息的源哪個(gè)死姚,下面是栗子:

image.png

http://www.otherapp.com/index.html
function postMessage(msg){
var targetWindow = parent.window;
targetWindow.postMessage(msg,"*”);//觸發(fā)消息事件
}
function handleReceive(msg){
var object = dojo.fromJson(msg);
if(object.status == “ok”){
//continue to do other things
……
}else{
//retry sending msg
……
}
}
window.addEventListener("message", handleReceive, false); //注冊(cè)監(jiān)聽(tīng)的事件
window.onLoad = function(){
postMessage("already loaded");
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末知允,一起剝皮案震驚了整個(gè)濱河市叙谨,隨后出現(xiàn)的幾起案子手负,更是在濱河造成了極大的恐慌,老刑警劉巖竟终,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件统捶,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡喘鸟,警方通過(guò)查閱死者的電腦和手機(jī)什黑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拣凹,“玉大人恨豁,你說(shuō)我怎么就攤上這事【漳洌” “怎么了扮匠?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我活箕,道長(zhǎng),這世上最難降的妖魔是什么克蚂? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任埃叭,我火速辦了婚禮,結(jié)果婚禮上赤屋,老公的妹妹穿的比我還像新娘。我一直安慰自己媚媒,他們只是感情好涩僻,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布逆日。 她就那樣靜靜地躺著,像睡著了一般室抽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上噩死,一...
    開(kāi)封第一講書(shū)人閱讀 51,301評(píng)論 1 301
  • 那天神年,我揣著相機(jī)與錄音,去河邊找鬼垛耳。 笑死飘千,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缔莲。 我是一名探鬼主播霉旗,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼读拆!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起暑诸,我...
    開(kāi)封第一講書(shū)人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤辟灰,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后笛洛,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體乃坤,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡湿诊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了仿畸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片朗和。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖千埃,靈堂內(nèi)的尸體忽然破棺而出忆植,到底是詐尸還是另有隱情,我是刑警寧澤朝刊,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布拾氓,位于F島的核電站,受9級(jí)特大地震影響织堂,放射性物質(zhì)發(fā)生泄漏奶陈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一潦俺、第九天 我趴在偏房一處隱蔽的房頂上張望徐勃。 院中可真熱鬧,春花似錦僻肖、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至余境,卻和暖如春灌诅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背即舌。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工关带, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人芜飘。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓磨总,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親娶牌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容