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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | < 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | < 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已经加载完成,可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | _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/
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库