iframe跨域通信的通用解决方案

简介:

2个信使的情况

一、背景

在这个Web页面越来越丰富的时代,页面通过iframe嵌入其他的页面也越来越常见。但由于浏览器同源策略的限制,不同域之间属性和操作是无法直接交互的,所以在这个时候,开发者多多少少需要一些方案来突破这些限制。跨域问题涉及的地方也很多,如文档之间的消息通信、ajax请求、Cookie等,本文讨论的是iframe和父页面的消息通信。

 

二、现状

目前网上也可以找到各种解决方案(少说都有10+个,有兴趣的话可以去看看),对于现代浏览器来说,原生的postMessage API一定是不二的选择,所以各种方案的不同点均在于IE 6、7中的处理(不用兼容IE6、7的同志可以去看其他文章了)。当然这么多方案有各种优缺点,甚至有些只支持单向跨域,个人觉得实际意义不大。另外一些方案需要proxy.html这样的代理页面做中转,但是涉及服务器上的部署,并且对于多方合作来说还是有些麻烦。

三、思路

虽然不再复述现有的各种方案,但还是想交待一点上下文。相信网上看到最多方案就是利用location.hash或是window.name进行iframe的跨域通信:

  • location.hash会直接暴露在URL里,并且在一些浏览器里会产生历史记录,数据安全性不高也影响用户体验,所以不做考虑。另外由于URL大小的限制,支持传递的数据量也不大。
  • window.name相比来讲就好很多了,支持2M的数据量,并且当iframe的页面跳到其他地址时,其window.name值保持不变,副作用可以说是最小的。

讲到这思路也比较清晰了,咱们就用window.name呗,但问题又来了:只有两个页面同域时才能访问window.name。这个问题还好,只要把iframe改为与父页面同域就可以了。这又衍生了新的问题:这不是意味着只能单向通信了吗,iframe怎么向父页面发消息(不可能去改父页面的location吧)?在暗骂坑爹的同时偶然发现了一个很神奇的方法,就是想访问一个iframe的window.name时,只要将其location改为‘about:blank’即可,屡试不爽~没错这个“特性”可以视为IE6/7的一项安全性问题,但利用这个特性来进行跨域通信并没有实际的安全风险。

具体的实现见下图,在iframe的内部再创建一个iframe(我们称之为信使),父子页面轮询信使的window.name,父子页面各自使用变量保存window.name,轮询时发现有变化即被视为收到消息。基本原理就是这么简单,我们继续..

1个信使的情况

图1

作为一个通用的解决方案,我们的目标是提供一个js文件,封装通信的接口,需要通信的页面只要加载js文件就行。但在封装前,需要考虑更复杂一点的情况:当父子页面双方频率较高地双向通信时,如何进行支持?按照上述的方案,信使的window.name并没有读写锁的概念,这意味着消息很容易乱掉或被漏掉。所以更好的方案应该是:创建两个信使,分别负责”父–>子”和”子–>父”的消息传递,并且为了防止消息被冲掉,发送消息时会维护一个消息队列,在取消息时处理消息队列里的所有消息。见图2。

2个信使的情况

图2

四、封装

最后的封装就是加入了postMessage API的检测,另外也要判断是否为跨域,这样就满足了所有iframe通信的情况了。这里实现的信使只负责消息的监听和发送,所以在使用上是非常简单的:

// 父页面中
// 初始化信使, 告知与其交互的iframe引用
var messenger = Messenger.initInParent(iframeEl);
 
// 监听消息
messenger.onmessage = function (data) {
          ...
};
 
// 发送消息
messenger.send(message);
// iframe中
// 初始化信使
var messenger = Messenger.initInIframe();
 
// 监听消息
messenger.onmessage = function (data) {
      ...
};
 
// 发送消息
messenger.send(message);

具体使用可以参考下方的demo : )

五、总结

虽然国内也有人提过使用”about:blank”进行iframe通信的,但是代码的封装和可读性都不是太好,本方案是一日本人所提出,我觉得处理的很好,所以就拿出来和大家分享下。虽然尝试过优化轮询那一块,但暂时无果,有兴趣的朋友可以一起研究下~

DEMO:点击这里

脚本下载:http://biqing.alloyteam.com/lab/messenger/messenger.js

GitHub:https://github.com/biqing/MessengerJS





本文转自Barret Lee博客园博客,原文链接:http://www.cnblogs.com/hustskyking/archive/2013/03/29/lightweight-solution-for-an-iframe-cross-domain-communication.html,如需转载请自行联系原作者

相关文章
|
6月前
|
安全 前端开发 JavaScript
跨域iframe通信
跨域iframe通信
|
8月前
|
移动开发 前端开发 安全
iframe实现跨域通信的方法
iframe实现跨域通信的方法
245 6
|
8月前
|
JavaScript
iframe 跨域通信和不跨域通信
iframe 跨域通信和不跨域通信
|
8月前
|
JSON JavaScript 前端开发
跨域的原理及解决方案
同源策略是Web应用程序安全性模型中的重要概念。根据该策略,Web浏览器允许第一个网页中包含的脚本访问第二个网页中的数据,但前提是两个网页具有相同的来源。来源由URI,主机名和端口号的组合定义。此策略可防止一个页面上的恶意脚本通过该页面的DOM(Document Object Model)获得对另一网页上敏感数据的访问。 JSONP 由于同源策略,一般来说位于server1.example.com...
|
前端开发 JavaScript 数据处理
【JavaScript】在前后端通信方面的优势
【JavaScript】在前后端通信方面的优势
78 0
|
前端开发 JavaScript 安全
带你读《现代Javascript高级教程》——前端跨页面通信:实现页面间的数据传递与交互(1)
带你读《现代Javascript高级教程》——前端跨页面通信:实现页面间的数据传递与交互
208 0
|
移动开发 安全 JavaScript
html5使用postMessage解决跨域和跨窗口消息传递的解决方案
html5使用postMessage解决跨域和跨窗口消息传递的解决方案
159 0
|
Web App开发 移动开发 安全
「趣学前端」关于iframe跨域通信
用技术实现梦想,用梦想打开创意之门。之前开发遇到了iframe跨域通信的问题,今天分享一下解决方案,顺便总结一波知识点。
994 1
「趣学前端」关于iframe跨域通信
|
人工智能 JSON 安全
《前端实战总结》之使用postMessage实现可插拔的跨域聊天机器人
由于笔者之前的项目中接触过聊天机器人的项目,主要实现机器人客服模块,以及支持跨多平台使用的目的,所以特地总结一下,希望有所收获。
293 0

热门文章

最新文章

下一篇
开通oss服务
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等