js如何解決跨域問題

JavaScript跨域總結(jié)與解決辦法

什么是跨域

1、document.domain+iframe的設(shè)置

2、動(dòng)態(tài)創(chuàng)建script

3、利用iframe和location.hash

4轻姿、window.name實(shí)現(xiàn)的跨域數(shù)據(jù)傳輸

5犁珠、使用HTML5 postMessage

6、利用flash

什么是跨域

JavaScript出于安全方面的考慮互亮,不允許跨域調(diào)用其他頁面的對象犁享。但在安全限制的同時(shí)也給注入iframe或是ajax應(yīng)用上帶來了不少麻煩。這里把涉及到跨域的一些問題簡單地整理一下:

首先什么是跨域豹休,簡單地理解就是因?yàn)镴avaScript同源策略的限制炊昆,a.com 域名下的js無法操作b.com或是c.a.com域名下的對象。更詳細(xì)的說明可以看下表:

URL說明是否允許通信

http://www.a.com/a.js

http://www.a.com/b.js

同一域名下允許

http://www.a.com/lab/a.js

http://www.a.com/script/b.js

同一域名下不同文件夾允許

http://www.a.com:8000/a.js

http://www.a.com/b.js

同一域名威根,不同端口不允許

http://www.a.com/a.js

https://www.a.com/b.js

同一域名凤巨,不同協(xié)議不允許

http://www.a.com/a.js

http://70.32.92.74/b.js

域名和域名對應(yīng)ip不允許

http://www.a.com/a.js

http://script.a.com/b.js

主域相同,子域不同不允許

http://www.a.com/a.js

http://a.com/b.js

同一域名洛搀,不同二級域名(同上)不允許(cookie這種情況下也不允許訪問)

http://www.cnblogs.com/a.js

http://www.a.com/b.js

不同域名不允許

特別注意兩點(diǎn):

第一敢茁,如果是協(xié)議和端口造成的跨域問題“前臺”是無能為力的,

第二:在跨域問題上姥卢,域僅僅是通過“URL的首部”來識別而不會去嘗試判斷相同的ip地址對應(yīng)著兩個(gè)域或兩個(gè)域是否在同一個(gè)ip上卷要。

“URL的首部”指window.location.protocol +window.location.host,也可以理解為“Domains, protocols and ports must match”独榴。

接下來簡單地總結(jié)一下在“前臺”一般處理跨域的辦法僧叉,后臺proxy這種方案牽涉到后臺配置,這里就不闡述了棺榔,有興趣的可以看看yahoo的這篇文章:《JavaScript: Use a Web Proxy for Cross-Domain XMLHttpRequest Calls

1瓶堕、document.domain+iframe的設(shè)置

對于主域相同而子域不同的例子,可以通過設(shè)置document.domain的辦法來解決症歇。具體的做法是可以在http://www.a.com/a.html和http://script.a.com/b.html兩個(gè)文件中分別加上document.domain = ‘a(chǎn).com’郎笆;然后通過a.html文件中創(chuàng)建一個(gè)iframe,去控制iframe的contentDocument忘晤,這樣兩個(gè)js文件之間就可以“交互”了宛蚓。當(dāng)然這種辦法只能解決主域相同而二級域名不同的情況,如果你異想天開的把script.a.com的domian設(shè)為alibaba.com那顯然是會報(bào)錯(cuò)地设塔!代碼如下:

www.a.com上的a.html

document.domain = 'a.com';

var ifr = document.createElement('iframe');

ifr.src = 'http://script.a.com/b.html';

ifr.style.display = 'none';

document.body.appendChild(ifr);

ifr.onload = function(){

? ? var doc = ifr.contentDocument || ifr.contentWindow.document;

? ? // 在這里操縱b.html

? ? alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue);

};

script.a.com上的b.html

document.domain = 'a.com';

這種方式適用于{www.kuqin.com, kuqin.com, script.kuqin.com, css.kuqin.com}中的任何頁面相互通信凄吏。

備注:某一頁面的domain默認(rèn)等于window.location.hostname。主域名是不帶www的域名闰蛔,例如a.com痕钢,主域名前面帶前綴的通常都為二級域名或多級域名,例如www.a.com其實(shí)是二級域名序六。 domain只能設(shè)置為主域名任连,不可以在b.a.com中將domain設(shè)置為c.a.com。

問題:

1例诀、安全性随抠,當(dāng)一個(gè)站點(diǎn)(b.a.com)被攻擊后裁着,另一個(gè)站點(diǎn)(c.a.com)會引起安全漏洞。

2拱她、如果一個(gè)頁面中引入多個(gè)iframe跨算,要想能夠操作所有iframe,必須都得設(shè)置相同domain椭懊。

2、動(dòng)態(tài)創(chuàng)建script

雖然瀏覽器默認(rèn)禁止了跨域訪問步势,但并不禁止在頁面中引用其他域的JS文件氧猬,并可以自由執(zhí)行引入的JS文件中的function(包括操作cookie、Dom等等)坏瘩。根據(jù)這一點(diǎn)盅抚,可以方便地通過創(chuàng)建script節(jié)點(diǎn)的方法來實(shí)現(xiàn)完全跨域的通信。具體的做法可以參考YUI的Get Utility

這里判斷script節(jié)點(diǎn)加載完畢還是蠻有意思的:ie只能通過script的readystatechange屬性倔矾,其它瀏覽器是script的load事件妄均。以下是部分判斷script加載完畢的方法。

js.onload = js.onreadystatechange = function() {

? ? if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') {

? ? ? ? // callback在此處執(zhí)行

? ? ? ? js.onload = js.onreadystatechange = null;

? ? }

};

3哪自、利用iframe和location.hash

這個(gè)辦法比較繞丰包,但是可以解決完全跨域情況下的腳步置換問題。原理是利用location.hash來進(jìn)行傳值壤巷。在url: http://a.com#helloword中的‘#helloworld’就是location.hash邑彪,改變hash并不會導(dǎo)致頁面刷新,所以可以利用hash值來進(jìn)行數(shù)據(jù)傳遞胧华,當(dāng)然數(shù)據(jù)容量是有限的寄症。假設(shè)域名a.com下的文件cs1.html要和cnblogs.com域名下的cs2.html傳遞信息,cs1.html首先創(chuàng)建自動(dòng)創(chuàng)建一個(gè)隱藏的iframe矩动,iframe的src指向cnblogs.com域名下的cs2.html頁面有巧,這時(shí)的hash值可以做參數(shù)傳遞用。cs2.html響應(yīng)請求后再將通過修改cs1.html的hash值來傳遞數(shù)據(jù)(由于兩個(gè)頁面不在同一個(gè)域下IE悲没、Chrome不允許修改parent.location.hash的值篮迎,所以要借助于a.com域名下的一個(gè)代理iframe;Firefox可以修改)檀训。同時(shí)在cs1.html上加一個(gè)定時(shí)器柑潦,隔一段時(shí)間來判斷l(xiāng)ocation.hash的值有沒有變化,一點(diǎn)有變化則獲取獲取hash值峻凫。代碼如下:

先是a.com下的文件cs1.html文件:

function startRequest(){

? ? var ifr = document.createElement('iframe');

? ? ifr.style.display = 'none';

? ? ifr.src = 'http://www.cnblogs.com/lab/cscript/cs2.html#paramdo';

? ? document.body.appendChild(ifr);

}

function checkHash() {

? ? try {

? ? ? ? var data = location.hash ? location.hash.substring(1) : '';

? ? ? ? if (console.log) {

? ? ? ? ? ? console.log('Now the data is '+data);

? ? ? ? }

? ? } catch(e) {};

}

setInterval(checkHash, 2000);

cnblogs.com域名下的cs2.html:

//模擬一個(gè)簡單的參數(shù)處理操作switch(location.hash){? ? case '#paramdo':? ? ? ? callBack();? ? ? ? break;? ? case '#paramset':? ? ? ? //do something……? ? ? ? break;}function callBack(){? ? try {? ? ? ? parent.location.hash = 'somedata';? ? } catch (e) {? ? ? ? // ie渗鬼、chrome的安全機(jī)制無法修改parent.location.hash,? ? ? ? // 所以要利用一個(gè)中間的cnblogs域下的代理iframe? ? ? ? var ifrproxy = document.createElement('iframe');? ? ? ? ifrproxy.style.display = 'none';? ? ? ? ifrproxy.src = 'http://a.com/test/cscript/cs3.html#somedata';// 注意該文件在"a.com"域下document.body.appendChild(ifrproxy);? ? }}

a.com下的域名cs3.html

//因?yàn)閜arent.parent和自身屬于同一個(gè)域荧琼,所以可以改變其location.hash的值

parent.parent.location.hash = self.location.hash.substring(1);

當(dāng)然這樣做也存在很多缺點(diǎn)譬胎,諸如數(shù)據(jù)直接暴露在了url中差牛,數(shù)據(jù)容量和類型都有限等……

4、window.name實(shí)現(xiàn)的跨域數(shù)據(jù)傳輸

文章較長列在此處不便于閱讀堰乔,詳細(xì)請看window.name實(shí)現(xiàn)的跨域數(shù)據(jù)傳輸偏化。

5、使用HTML5 postMessage

HTML5中最酷的新功能之一就是跨文檔消息傳輸Cross Document Messaging镐侯。下一代瀏覽器都將支持這個(gè)功能:Chrome 2.0+侦讨、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。 Facebook已經(jīng)使用了這個(gè)功能苟翻,用postMessage支持基于web的實(shí)時(shí)消息傳遞韵卤。

otherWindow.postMessage(message, targetOrigin);

otherWindow:?對接收信息頁面的window的引用〕缑ǎ可以是頁面中iframe的contentWindow屬性沈条;window.open的返回值;通過name或下標(biāo)從window.frames取到的值诅炉。

message:?所要發(fā)送的數(shù)據(jù)蜡歹,string類型。

targetOrigin:?用于限制otherWindow涕烧,“*”表示不作限制

a.com/index.html中的代碼:

window.onload = function() {? ? var ifr = document.getElementById('ifr');? ? var targetOrigin = 'http://b.com';// 若寫成'http://b.com/c/proxy.html'效果一樣// 若寫成'http://c.com'就不會執(zhí)行postMessage了ifr.contentWindow.postMessage('I was there!', targetOrigin);};

b.com/index.html中的代碼:

? ? window.addEventListener('message', function(event){

? ? ? ? // 通過origin屬性判斷消息來源地址

? ? ? ? if (event.origin == 'http://a.com') {

? ? ? ? ? ? alert(event.data);? ? // 彈出"I was there!"

? ? ? ? ? ? alert(event.source);? // 對a.com月而、index.html中window對象的引用

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 但由于同源策略,這里event.source不可以訪問window對象

? ? ? ? }

? ? }, false);


6议纯、利用flash

這是從YUI3的IO組件中看到的辦法景鼠,具體可見http://developer.yahoo.com/yui/3/io/

可以看在Adobe Developer Connection看到更多的跨域代理文件規(guī)范:ross-Domain Policy File Specifications痹扇、HTTP Headers Blacklist铛漓。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌紧憾,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件包晰,死亡現(xiàn)場離奇詭異,居然都是意外死亡炕吸,警方通過查閱死者的電腦和手機(jī)伐憾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赫模,“玉大人树肃,你說我怎么就攤上這事∑俾蓿” “怎么了胸嘴?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵雏掠,是天一觀的道長。 經(jīng)常有香客問我劣像,道長乡话,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任耳奕,我火速辦了婚禮绑青,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘屋群。我一直安慰自己时迫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布谓晌。 她就那樣靜靜地躺著,像睡著了一般癞揉。 火紅的嫁衣襯著肌膚如雪纸肉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天喊熟,我揣著相機(jī)與錄音柏肪,去河邊找鬼。 笑死芥牌,一個(gè)胖子當(dāng)著我的面吹牛烦味,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播壁拉,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼谬俄,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了弃理?” 一聲冷哼從身側(cè)響起溃论,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎痘昌,沒想到半個(gè)月后钥勋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡辆苔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年算灸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片驻啤。...
    茶點(diǎn)故事閱讀 40,861評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡菲驴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出骑冗,到底是詐尸還是另有隱情谢翎,我是刑警寧澤捍靠,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站森逮,受9級特大地震影響榨婆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜褒侧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一良风、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧闷供,春花似錦烟央、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至婿失,卻和暖如春钞艇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背豪硅。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工哩照, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人懒浮。 一個(gè)月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓飘弧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親砚著。 傳聞我的和親對象是個(gè)殘疾皇子次伶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評論 2 361

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

  • 大家好学少,我是IT修真院鄭州分院第一期的學(xué)員胡嘉杰,一枚正直純潔善良的WEB前端程序員秧骑。 今天給大家分享一下版确,修真院...
    ithinker5閱讀 498評論 0 1
  • 1. 什么是跨域? 跨域一詞從字面意思看乎折,就是跨域名嘛绒疗,但實(shí)際上跨域的范圍絕對不止那么狹隘。具體概念如下:只要協(xié)議...
    他在發(fā)呆閱讀 824評論 0 0
  • 1. 什么是跨域骂澄? 跨域一詞從字面意思看吓蘑,就是跨域名嘛,但實(shí)際上跨域的范圍絕對不止那么狹隘。具體概念如下:只要協(xié)議...
    w_zhuan閱讀 519評論 0 0
  • 原文地址:原文地址 什么是跨域磨镶? 跨域是指一個(gè)域下的文檔或腳本試圖去請求另一個(gè)域下的資源溃蔫,這里跨域是廣義的。 廣義...
    C_Y大漁閱讀 1,259評論 1 13
  • 愛,讓我們傾其所有脐嫂,在所不惜…… 微信名:Sophia 昵稱:安然 給女兒的一封信…… “好快呀统刮!女兒今天要回來了...
    Sophia安然閱讀 262評論 0 3