iframe間的跨域通信


1,跨域的一個示例

當你需要操作一個內嵌iframe是,如果這個內嵌iframe和打開的網站不在同一個域中,你時常會遇到這樣的報錯:

Unsafe JavaScript attempt to access frame with URL http:/www.d1.com from frame with URL http://www.d2.com. Domains, protocols and ports must match.

從報錯信息中我們可以知道,瀏覽器是通過域名(domain),協議(HTTP),端口(Port)。也就是說這三點只要有一個不匹配那就是跨域(Cross domain)。

對於跨域,我們通常的解決辦法是在原來的域添加一個文件,用該文件作為中間人來實現跨域。也就是說,先發消息到該文件,由該文件再操作同域的HTML。

HTML 5給我們帶來了安全的跨域通信接口,即window.postMessage()方法。它方法原型是:

window.postMessage(msg, domain);

我們可以給指定的domain發送msg。而接收msg的iframe只要注冊一個監聽事件就可以了。我們看示例:

www.d1.com/a.html

<html>
<head>
	<title>operate the iframe on other domain</title>
	<script>
		function sendMessage(){
			var frm = document.getElementById("iframe1");
			frm.contentWindow.postMessage("hello","*")
		}
	</script>
</head>
<body>
	<input id="send" type="button" onclick="sendMessage()" value="send message" />
	<br />
	<iframe style="width:300px; height:400px;" id="iframe1" src="http://www.d2.com/b.html">
	</iframe>
</body>
</html>

我們再看看監聽的那個iframe

www.d2.com/b.html

<html>
<head>
	<title>a frame which receive the message</title>
	<script>
		var OnMessage = function (e) {
			alert(e.data);
		}
		function init() {
			if (window.addEventListener) {  // all browsers except IE before version 9
				window.addEventListener("message", OnMessage, false);
			} else {
				if (window.attachEvent) {   // IE before version 9
				window.attachEvent("onmessage", OnMessage);
				}
			}
       	 	};
       		init();
	</script>
</head>
<body>
	<p>a iframe to receive the message</p>
</body>
</html>

在監聽處理函數中我們可以判斷具體的那個domain發來的消息。

2,瀏覽器支持

IE8+, FF3+, Chrome, Safari

IE8中需要注意的是msg這個參數只能是string,而其他瀏覽器支持JavaScript的object。變通辦法就是發送一個在發送時JSON.stringfy格式化一下,而在接受端JSON.parse就可以了。

如果有向后兼容的需要,可以考慮這個Hack: Backwards compatible window.postMessage()

Update:2012-08-30

前些日子我發現Tecent的一個Team的Blog的一篇文章,利用”about:blank”很好地解決的IE6和IE7下的iframe跨域問題,具體請猛擊:iframe跨域通信的通用解決方案

3,注意事項

如果你在接受消息的iframe中通過JavaScript來修改DOM元素。要確保iframe已經加載完成,可以這樣做:

_overlay = document.getElementById("iframe1");
if(_overlay.attachEvent){
	_overlay.attachEvent("onreadystatechange", function(){
	   if(_overlay.readyState === "complete" || _overlay.readyState == "loaded"){
	   		 _overlay.detachEvent( "onreadystatechange", arguments.callee);
			sendMessage();
	   }
	});
} else {
	if(_overlay.addEventListener){
	    _overlay.addEventListener( "load", function(){
			 this.removeEventListener( "load", arguments.call, false);
			 sendMessage();
		}, false);
	}
}


 

參考:
---------------------------------------------------------------------------------------

http://blog.css-js.com/javascript/javascript-iframe-readystate.html

http://msdn.microsoft.com/en-us/library/ie/cc197015(v=vs.85).aspx

https://developer.mozilla.org/en-US/docs/DOM/window.postMessage

http://www.alloyteam.com/2012/08/lightweight-solution-for-an-iframe-cross-domain-communication/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM