IE下因設置document.domain而無法和Iframe通信的解決方法(SCRIPT5: 拒絕訪問)[轉]
最近在開發SDK的過程中發現IE下有個很怪異的問題:在同一域下,因在父頁面上設置了document.domain,而導致無法正常和Iframe(也是同域下)進行通信,IE下拋出的錯誤是:SCRIPT5: 拒絕訪問,導致無法操作iframe中的內容。
經過查閱了很多資料后發現IE下,在父頁面或在iframe頁面中,只要設置了document.domain,無論是和當前域名相同還是根域名,均視為跨域,所以才會出現拒絕訪問的錯誤,即使你這樣寫document.domain=document.domain;雖然好像沒人這么干。
那么如何才能解決這個問題,讓父頁面和iframe頁面正常通信呢,根據同源策略,讓雙方均設置同樣的domain就可以達到目的。
比如頁面A是http://www.a.com/a.html ,頁面B是http://www.a.com/b.html, 這時候兩個頁面中都寫上document.domain=”aaa.com”,這樣兩個頁面就可以交互了。
但是,上面的情況只適用於嵌入的頁面是事先已經已<iframe src=”http://www.a.com/b.html”></iframe>的形式在頁面中寫好了,而如果是在頁面中動態創建的iframe標簽再指定其src為http://www.a.com/b.html,上面的方法就不適用 了。
此種情況及解決方法請直接參考原著:IE下Iframe的 document.domain的怪異問題
上面的這種情況是當Iframe的src不為空,即存在實際的引用頁面的解決方法。但如果需要創建一個空白的iframe(即src不指定),還要想拿到iframe里的document對象呢?看個例子:
//訪問地址:http://www.a.com/a.html
<html>
<head>
<title>Iframe</title>
</head>
<body>
<script type=
"text/javascript"
>
document.domain =
'a.com'
;
var
iframe = document.createElement(
"iframe"
);
document.body.appendChild(iframe);
iframe.onload =
function
() {
console.log(iframe.contentWindow.document.location)
}
</script>
</body>
</html>
有人想到設置iframe里面的domain,思路正確,但由於父頁面已經設置了domain,在父頁面中根本無法獲取到空白iframe的document對象,也就無法設置iframe的domain。
后來經過了很多嘗試,也研究了twitter的SDK的代碼,找到了解決方案:
通過設置iframe的src來執行一段JS代碼,如下,
1
iframe.src =
"javascript:void((function(){document.open();document.domain='"
+ document.domain +
"';document.close()})())"
;
通過這種方式就可以改寫iframe里面的domain了,這和在瀏覽器地址欄里輸入這段代碼的功效一樣,這種方式像是旁門左道,但是這確實奏效了。
於是上面的代碼更改為:
//訪問地址:http://www.a.com/a.html
<html>
<head>
<title>Iframe</title>
</head>
<body>
<script type=
"text/javascript"
>
document.domain =
'a.com'
;
var
iframe = document.createElement(
"iframe"
);
document.body.appendChild(iframe);
try
{
iframe.contentWindow.document;
}
catch
(e) {
iframe.src =
"javascript:void((function(){document.open();document.domain='"
+ document.domain +
"';document.close()})())"
;
console.log(iframe.contentWindow.document.location)
}
</script>
</body>
</html>
在IE9下測試順利通過,運行結果:http://www.a.com/a.html,至此,問題看似已經解決。 於是在其他版本的IE瀏覽器下做測試,結果出人意料,IE6-IE8均仍報錯“拒絕訪問”,頭疼,經過反復嘗試,后來無意間在設置iframe.src后,使用了setTimeout來獲取iframe里的內容,靠,居然不報錯了。看來是設置iframe的domain和獲取iframe里面的內容這兩個操作存在異步問題。
然后將上面方法改進:
//訪問地址:http://www.a.com/a.html
<html>
<head>
<title>Iframe</title>
</head>
<body>
<script type=
"text/javascript"
>
document.domain =
'a.com'
;
var
iframe = document.createElement(
"iframe"
);
document.body.appendChild(iframe);
if
(/msie/i.test(navigator.userAgent)){
try
{
iframe.contentWindow.document;
}
catch
(e) {
iframe.onload =
function
() {
console.log(iframe.contentWindow.document.location);
iframe.onload =
null
;
}
iframe.src =
"javascript:void((function(){document.open();document.domain='"
+ document.domain +
"';document.close()})())"
;
}
}
</script>
</body>
</html>
再次在各IE下做測試,順利通過!至此父頁面因設置了document.domain而導致無法正常和同域下用js動態創建的iframe正常通信的問題徹底得到解決!如果你在開發過程中遇到類似問題,不妨嘗試下這種方法,如果你有更好的解決方案,希望能公開出來供大家一起學習,討論。Demo地址。