`

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

 
阅读更多

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

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通信的情况了。这里实现的信使只负责消息的监听和发送,所以在使用上是非常简单的:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
// 父页面中
// 初始化信使, 告知与其交互的iframe引用
var messenger = Messenger.initInParent(iframeEl);
 
// 监听消息
messenger.onmessage = function (data) {
          ...
};
 
// 发送消息
messenger.send(message);
JavaScript
1
2
3
4
5
6
7
8
9
10
11
// iframe中
// 初始化信使
var messenger = Messenger.initInIframe();
 
// 监听消息
messenger.onmessage = function (data) {
      ...
};
 
// 发送消息
messenger.send(message);

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

五、总结

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

 

 

 

分享到:
评论

相关推荐

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

    标题中的“iframe跨域通信的通用解决方案-第二弹!(终极解决方案)”指的是在Web开发中,使用`iframe`元素进行跨域通信的一种高级技术。跨域通信是Web应用程序中常见的需求,特别是在需要集成不同来源的网页内容或者...

    Javascript跨域访问解决方案

    这种方法常用于嵌入式框架(如iframe)的跨域通信。 7. document.domain 对于同一二级域名下的不同子域名,可以设置`document.domain`为相同的值,实现跨子域通信。但这仅限于同一顶级域名下。 总结来说,...

    js跨域问题解决方案.

    如果子域和父域是相同的顶级域名,可以通过设置`document.domain`为相同的值,实现子域和父域之间的跨域通信。 #### 3.5 postMessage API `postMessage`允许不同源的窗口之间进行通信,通过`window.postMessage()`...

    基于iframe的跨域与更新父窗体地址栏的解决方案.docx

    ### 基于iframe的跨域与更新父窗体地址栏的解决方案 #### 1. 需求介绍 在现代Web应用开发中,经常会出现需要在一个应用中嵌入另一个应用的情况,尤其是在需要集成第三方服务或功能时。本文档探讨了一个特定场景:...

    解决ajax跨域问题

    在实际项目中,开发者需要根据具体情况选择合适的跨域解决方案。例如,JSONP适用于简单的GET请求,而CORS则更通用,支持各种HTTP方法。同时,注意跨域安全问题,避免因不当配置导致的安全风险。

    链接修改及跨域访问的问题

    为了在不同软件系统间实现跨域通信,开发者需要采取一些技术手段来绕过这个限制。本文将详细讨论如何在JavaScript中实现跨域访问,以及涉及到的`LinkToInfoFrame`、`ShowModelInfo`、`ShowLineData`等方法的修改。 ...

    JavaScript 跨域之POST实现方法

    在互联网编程中,由于浏览器的同源策略限制,跨域请求成为了一个常见问题。当两个不同的域之间互相访问资源时,便...此外,如果可能的话,使用支持CORS(跨源资源共享)的服务器配置会是一个更为简洁和安全的解决方案。

    Ajax 跨域如何实现

    关于Ajax跨域实现的知识点,首先需要明白什么是Ajax跨域问题。在Web开发中,出于安全考虑,浏览器会限制网页只能与自己的域进行通信,...而对于需要同其他公司、其他域进行交互的情况,CORS提供了更为通用的解决方案。

    javascript跨域的4种方法和原理详解.docx

    CORS 是一种更为通用的跨域解决方案,它允许服务器通过 HTTP 头部信息来指定哪些域可以访问其资源。 **原理:** 1. **预检请求**:对于复杂的请求(如 POST、PUT 等),浏览器会先发送一个 OPTIONS 请求来检查...

    document.frames在非IE浏览器中的解决办法

    #### 解决方案:使用`window.frames` 针对`document.frames`在非IE浏览器中的兼容性问题,一个通用且被广泛采用的解决方案是使用`window.frames`。`window.frames`是所有现代浏览器都支持的标准API,它可以用来获取...

    父子页面相互调用总结

    然而,由于其兼容性问题(不被其他现代浏览器支持),现在已经被广泛弃用,开发者应转向更通用的解决方案。 接着是`window.open`,这是一个在所有现代浏览器中都支持的函数,用于打开新的浏览器窗口或标签。通过...

    js实现跨域访问的三种方法

    这种方法主要依赖于JSONP(JSON with Padding)技术,它是一种通过动态script标签请求数据的解决方案。当需要获取其他域的数据时,可以构建一个script标签,其src属性指向目标URL,并带上一个回调函数名作为参数。...

    part3 JS Additional articles.pdf

    这种技术在早期网页设计中非常流行,但随着现代网页标准的发展,frames 已经逐渐被淘汰,取而代之的是更灵活的解决方案如 iframe 和单页应用。 **Windows** 指的是浏览器中的窗口对象,它是 `window` 对象的原型。...

    淘宝的HTML5实践

    这款工具最初不兼容Internet Explorer,而是采用了HTML5的跨文档消息传递功能(Cross Document Messaging),而非传统的iframe跨域方法。 - **技术细节**:使用了HTML5的WebSocket技术替代了传统的Ajax轮询,提高了...

    top.location.href 没有权限 解决方法

    在遇到此类问题时,可以尝试使用`try...catch`结构配合指定URL来规避跨域限制,但应谨慎处理,因为这不是一种通用的解决方案,且可能受到用户浏览器设置的影响。对于跨域通信的最佳实践,建议使用现代浏览器支持的...

    microfrontend-event-bus

    在这样的架构下,组件之间的通信变得复杂,因为它们可能属于不同的技术栈,而事件总线则为解决这个问题提供了一个通用的桥梁。 事件总线是一种设计模式,它允许不同组件之间通过发布和订阅事件来进行通信,而无需...

    C#后台调用前台JS函数方法

    这三种方法提供了不同场景下的解决方案,让C#后台能够灵活地调用前端JavaScript函数。第一种方法简单且直接,适用于简单的交互。第二种方法更通用,尤其适用于需要在页面回发后执行JavaScript的场合。第三种方法适用...

Global site tag (gtag.js) - Google Analytics