一年前,我发过一篇关于跨文档通信方案的文章《iframe跨域通信的通用解决方案》,提供了一种基于创建iframe与轮询window.name的方案。

一年后,很高兴地带来彻底改造的新版本。实际上新方案已经用了很久了,一直没有时间抽象出来,最近终于挤时间分享出来了!~

回望过去

第一版的方案还是有不少问题,这里统一回复与总结一下。第一次使用MessengerJS的同学,可以直接跳到下面的“新版使用”小节。

无法使用的反馈

第一版方案,在一定程度上可以解决iframe通信的问题,但从大家的反馈上看,还是存在一些不足。这里列举一下评论里反馈的问题:

  • HTTP与HTTPS,无法通信
  • IE6在某些设置下,无法通信
  • js设置document.domain后,无法通信
*上述问题本人并未全部确认

性能有损

第一版方案,需要在内层的iframe中创建两个iframe,并且需要跑定时器轮询window.name,其性能必然有所损耗,更不要说在IE6/7下执行这样的操作。如果父窗口要与两个iframe通信,那么性能的问题也会成倍增长。

API不一致

第一版方案,为父窗口和iframe提供了不同的API。这样的设计并不友好,使用者应该把每个窗口对象统一对待。

多iframe通信?

多个iframe无法直接通信,需要父窗口中转才行。

问题新版都解决了?

那是必须的,上述问题全部得以解决,更重要的是,代码量还减少了50%+!

新方案原理概述

概念上,方案的理念还是使用“信使”概念,即 Messenger。

对于现代浏览器,postMessage API还是无可撼动的。IE6/7下,使用的是一个被认为是bug或安全漏洞的特性,即navigator对象在父窗口和iframe之间是共享的。 基于这一点,我们可以在父窗口中,在navigator对象上注册一个消息回调函数;在iframe中,调用navigator上的这个函数并传入参数。 此时可看作,iframe往父窗口的一个函数传递了一个参数,并在父窗口的上下文中执行了,那么就相当于iframe向父窗口发送了一条消息。反之亦然。

原理就是这么简单(这次我连图都不用画了),好处也是很明显的:

  • 该方案不依赖浏览器的各项设计,不受设置影响,同时完美支持HTTPS
  • 不用创建多余iframe,基于接口调用,不需要轮询,性能大幅提升
  • 良好的接口封装,所有窗口对象统一对待
  • 多iframe也不怕,navigator对象的共享,让iframe之间直接通信成为可能

关于安全性

有些同学认为上述方案存在安全风险,也有在wuyun反馈这类问题,但微软并没有去修改。

其实并不用担心,这里做个简单说明:

我们只将消息回调函数注册在navigator对象上,虽然任何引入的脚本或页面,都可以向navigator上发消息,但这其实和 postMessage不限域的情况并无差异。这里对开发者的建议是,传递消息使用JSON String的形式,使用一个字段做消息有效性的验证。如果怕一个固定值(如项目名)不安全,可以使用一个简单的加密算法,并对业务脚本进行压缩混淆,此 时的安全风险可以降到最低。

好处说完了,怎么用?

  1. 在需要通信的文档中(父窗口和iframe们), 都确保引入MessengerJS
  2. 每一个文档(document), 都需要自己的Messenger与其他文档通信. 即每一个window对象都对应着一个, 且仅有一个Messenger对象, 该Messenger对象会负责当前window的所有通信任务. 每个Messenger对象都需要唯一的名字, 这样它们才可以知道跟谁通信.
    // 父窗口中 - 初始化Messenger对象
    var messenger = new Messenger('Parent');// iframe中 - 初始化Messenger对象
    var messenger = new Messenger('iframe1');// 多个iframe, 使用不同的名字
    var messenger = new Messenger('iframe2');
  3. 在发送消息前, 确保目标文档已经监听了消息事件.
    // iframe中 - 监听消息
    // 回调函数按照监听的顺序执行
    messenger.listen(function(msg){alert("收到消息: " + msg);
    });
  4. 父窗口想给iframe发消息, 它怎么知道iframe的存在呢? 添加一个消息对象吧.
    // 父窗口中 - 添加消息对象, 明确告诉父窗口iframe的window引用与名字
    messenger.addTarget(iframe1.contentWindow, 'iframe1');// 父窗口中 - 可以添加多个消息对象
    messenger.addTarget(iframe2.contentWindow, 'iframe2');
  5. 一切ready, 发消息吧~ 发送消息有两种方式. (以父窗口向iframe发消息为例)
    // 父窗口中 - 向单个iframe发消息
    messenger.targets['iframe1'].send(msg1);
    messenger.targets['iframe2'].send(msg2);// 父窗口中 - 向所有目标iframe广播消息
    messenger.send(msg);
  6. 现在看到iframe收到消息的alert提示了吗?

更多

Demo: http://biqing.github.io/labs/messenger/parent.html

项目主页:http://biqing.github.io/MessengerJS/

欢迎反馈,使用中遇到问题一定要告诉我哟!

原文:http://www.alloyteam.com/2013/11/the-second-version-universal-solution-iframe-cross-domain-communication/

iframe跨域通信的通用解决方案-第二弹!(终极解决方案)相关推荐

  1. iframe跨域通信

    在非跨域的情况下,可以通过 [父调子] iframe的dom节点.contentWindow [子调父]window.top/window.parent 来相互通信 在跨域情况下,可以使用postMe ...

  2. vue内嵌iframe跨域通信

    1.Vue组件中如何引入iframe? <template><div class="act-form"><iframe :src="src& ...

  3. 利用iframe实现ajax 跨域通信的解决方案

    在漫长的前端开发旅途上,无可避免的会接触到ajax,而且一般情况下都是用在同一域下的ajax请求:但是如果请求是发生在不同的域下,请求就无法执行,并且会抛出异常提示不允许跨域请求,目前我没有找到明确的 ...

  4. vue页面内嵌iframe使用postMessage进行跨域通信

    跨域 关于跨域的详细资料:跨域,这里只需要明确什么情况下跨域了(等同于两个url什么情况下是非同源关系). 协议.域名.端口三者有其一不同,就算是跨域,就算是非同源 本地环境模拟 借助phpstudy ...

  5. Cookie 跨域解决方案(IFrame跨域)

    IFrame跨域思路:假设有a.haorooms.com/text.html和b.haorooms.com/text.html两个页面,通过a.haorooms.com/text.html页面去修改b ...

  6. QQ登录IE下iframe跨域session和cookie失效问题的解决方案

    情景:webQQ登录,使用的是跨站点iframe弹窗登录,发现只有在IE浏览器下,登录存储session不起作用,一刷新页面就登出 分析:IE限制第三方session/cookie 随着IE版本的不断 ...

  7. ajax跨域,这应该是最全的解决方案了

    前言 从刚接触前端开发起,跨域这个词就一直以很高的频率在身边重复出现,一直到现在,已经调试过N个跨域相关的问题了,16年时也整理过一篇相关文章,但是感觉还是差了点什么,于是现在重新梳理了一下. 个人见 ...

  8. 服务端转发html页面,html5关于外链嵌入页面通信问题(postMessage解决跨域通信)

    说起来挺简单的,可以直接去查询postMessage推送和window.addEventListener接收使用方式,能自己搞明白是最好的,本文章也只是记录一下自己的使用方式 使用postMessag ...

  9. 【JavaScript】父子页面之间跨域通信的方法

    由于同源策略的限制,JavaScript跨域的问题,一直是一个比较棘手的问题,为了解决页面之间的跨域通信,大家煞费苦心,研究了各种跨域方案.之前也有小网同学分享过一篇"跨域,不再纠结&quo ...

最新文章

  1. 10061 mysql,Navicat无法连接到MySQL server的10061错误
  2. 4.5.1 RIP协议与距离向量算法
  3. include(),include_once(),requice(),require_once()的区别
  4. 用java分组查elasticsearch
  5. 学习之路十四:客户端调用WCF服务的几种方法小议
  6. STM32学习心得一:FlyMcu软件配置(STM32串口下载软件)
  7. java wsimport 调用_Java如何基于wsimport调用wcf接口
  8. python操作selenium
  9. 瀚高数据库开启Oracle兼容模块
  10. 从文本生成场景图(1)——SPICE:Semantic Propositional Image Caption Evaluation
  11. Cisco2960交换机密码破解方法
  12. 央视就《新闻联播》“火炬手空手捐款”致歉
  13. 360 ie8兼容模式 网页兼容问题
  14. C语言数据类型谜题总结
  15. Word中插入多张图片/论文图片排版的方法
  16. LVS负载均衡集群——NAT
  17. 在华为工作的优点和缺点
  18. 解决redis缓存穿透、redis缓存雪崩问题
  19. 视觉检测技术帮助制造业提升生产效率
  20. python中的pickle是什么意思_python中pickle模块浅析

热门文章

  1. 亲戚(信息学奥赛一本通-T1389)
  2. 阿克曼(Ackmann)函数(信息学奥赛一本通-T1163)
  3. 信息学奥赛C++语言:旗手
  4. 9 WM配置-主数据-定义物料分阶段的范围(Staging Area)
  5. 39 FI配置-财务会计-固定资产-组织结构-定义号码范围间隔
  6. 查看openssh版本_OpenSSH命令注入漏洞复现(CVE202015778)
  7. python 生成html_Python使用pyh生成HTML文档的方法示例
  8. DataSet and DataStream
  9. [弹性力学]应力转轴公式和应变转轴公式的展开式
  10. caffe SigmoidCrossEntropyLossLayer