1、document.domain+iframe的設(shè)置
2、動(dòng)態(tài)創(chuàng)建script
4轻姿、window.name實(shí)現(xiàn)的跨域數(shù)據(jù)傳輸
什么是跨域
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铛漓。