JS跨域之window.name實(shí)現(xiàn)的跨域數(shù)據(jù)傳輸
一、 window.name的性質(zhì)
window.name
有一個(gè)奇妙的性質(zhì),
頁(yè)面如果設(shè)置了window.name
,那么在不關(guān)閉頁(yè)面的情況下,
即使進(jìn)行了頁(yè)面跳轉(zhuǎn)location.href=...
,這個(gè)window.name
還是會(huì)保留。
我們可以在控制臺(tái)做一下實(shí)驗(yàn):
// 打開(kāi)瀏覽器輸入U(xiǎn)RL:www.dbjr.com.cn //F12打開(kāi)控制臺(tái) //在控制臺(tái)中依次輸入下面內(nèi)容 //輸入 window.name; //返回 '' //輸入 window.name='test'; //返回 'test' //輸入 location.; //返回 http://www.baidu.com //輸入 window.name; //返回 'test'
利用這一點(diǎn),我們就可以拿到其他域中的數(shù)據(jù)了。
二、 跨域請(qǐng)求
我們知道,使用iframe
的src
屬性,可以加載不同域中的網(wǎng)頁(yè),
我們也可以使用$('iframe').contentWindow
來(lái)拿到iframe
中頁(yè)面的window
對(duì)象,
只是這個(gè)window
對(duì)象中可以訪問(wèn)的屬性是很少的。
//控制臺(tái)輸入 Object.keys($('iframe').contentWindow); //返回 ["postMessage", "blur", "focus", "close", "parent", "opener", "top", "length", "frames", "closed", "location", "self", "window"]
訪問(wèn)其他屬性,會(huì)報(bào)錯(cuò):
Uncaught DOMException: Blocked a frame with origin "..." from accessing a cross-origin frame.
而如果使用iframe加載同域的頁(yè)面,訪問(wèn)$('iframe').contentWindow
的屬性是不會(huì)報(bào)錯(cuò)的,它就是iframe
內(nèi)頁(yè)面的完整的window
對(duì)象。
三、整合
利用window.name
的性質(zhì),我們可以在iframe
中加載一個(gè)跨域頁(yè)面。
這個(gè)頁(yè)面載入之后,讓它設(shè)置自己的window.name
,
然后再讓它進(jìn)行當(dāng)前頁(yè)面的跳轉(zhuǎn),跳轉(zhuǎn)到與iframe外的頁(yè)面同域的頁(yè)面,
此時(shí)window.name
是不會(huì)改變的。
這樣,iframe
內(nèi)外就屬于同一個(gè)域了,且window.name
還是跨域的頁(yè)面所設(shè)置的值。
假設(shè)有三個(gè)頁(yè)面:
a.com/app.html:應(yīng)用頁(yè)面。
a.com/proxy.html:代理文件,一般是一個(gè)沒(méi)有任何內(nèi)容的html文件,需要和應(yīng)用頁(yè)面在同一域下。
b.com/data.html:應(yīng)用頁(yè)面需要獲取數(shù)據(jù)的頁(yè)面,可稱(chēng)為數(shù)據(jù)頁(yè)面。
實(shí)現(xiàn)起來(lái)基本步驟如下:
在應(yīng)用頁(yè)面(a.com/app.html)中創(chuàng)建一個(gè)iframe,把其src指向數(shù)據(jù)頁(yè)面(b.com/data.html)。
數(shù)據(jù)頁(yè)面會(huì)把數(shù)據(jù)附加到這個(gè)iframe的window.name上,data.html代碼如下:
<script type="text/javascript"> window.name = 'I was there!'; // 這里是要傳輸?shù)臄?shù)據(jù),大小一般為2M,IE和firefox下可以大至32M左右 // 數(shù)據(jù)格式可以自定義,如json、字符串 </script>
在應(yīng)用頁(yè)面(a.com/app.html)中監(jiān)聽(tīng)iframe的onload事件,在此事件中設(shè)置這個(gè)iframe的src指向本地域的代理文件(代理文件和應(yīng)用頁(yè)面在同一域下,所以可以相互通信)。app.html部分代碼如下:
<script type="text/javascript"> var state = 0, iframe = document.createElement('iframe'), loadfn = function() { if (state === 1) { var data = iframe.contentWindow.name; // 讀取數(shù)據(jù) alert(data); //彈出'I was there!' } else if (state === 0) { state = 1; iframe.contentWindow.location = "http://a.com/proxy.html"; // 設(shè)置的代理文件 } }; iframe.src = 'http://b.com/data.html'; if (iframe.attachEvent) { iframe.attachEvent('onload', loadfn); } else { iframe.onload = loadfn; } document.body.appendChild(iframe); </script>
獲取數(shù)據(jù)以后銷(xiāo)毀這個(gè)iframe,釋放內(nèi)存;這也保證了安全(不被其他域frame js訪問(wèn))。
<script type="text/javascript"> iframe.contentWindow.document.write(''); iframe.contentWindow.close(); document.body.removeChild(iframe); </script>
總結(jié)起來(lái)即:
iframe的src屬性由外域轉(zhuǎn)向本地域,跨域數(shù)據(jù)即由iframe的window.name從外域傳遞到本地域。這個(gè)就巧妙地繞過(guò)了瀏覽器的跨域訪問(wèn)限制,但同時(shí)它又是安全操作。
參考文章:window.name Transport、Session variables without cookies
另一篇 JS跨域(Access-Control-Allow-Origin)前后端解決方案詳解 有更詳細(xì)的關(guān)于瀏覽器跨域問(wèn)題介紹
相關(guān)文章

JavaScript面試開(kāi)發(fā)常用的知識(shí)點(diǎn)總結(jié)

下載網(wǎng)站打開(kāi)頁(yè)面后間隔多少時(shí)間才顯示下載鏈接地址的代碼

JavaScript中展開(kāi)運(yùn)算符及應(yīng)用的實(shí)例代碼

JavaScript實(shí)現(xiàn)點(diǎn)擊按鈕就復(fù)制當(dāng)前網(wǎng)址

JavaScript實(shí)現(xiàn)的一個(gè)計(jì)算數(shù)字步數(shù)的算法分享

JavaScript實(shí)現(xiàn)簡(jiǎn)易聊天對(duì)話(huà)框(加滾動(dòng)條)

關(guān)于元素的尺寸(dimensions) 說(shuō)明