iframe跨域通信方法(转自http://www.2cto.com/kf/201211/166555.html)
来源:互联网 发布:网络支付安全问题 编辑:程序博客网 时间:2024/04/30 13:06
对于双向跨域通信来说,选择的方案也不是很多,综合各种因素,我们选择FIM + window.postMessage的组合方式来解决跨域通信问题。因为这两种方式各有优缺点,window.postMessage,使用非常简单,但是由于是个比较新的方法,IE6和IE7等老式浏览器不支持。FIM方法支持所有的浏览器,但比较繁琐,而且容易产生浏览记录,因此如果浏览器支持window.postMessage就采用window.postMessage,否则就采用FIM技术。
window.postMessage解决方案
window.postMessage是HTML5定义的一个很新的方法,这个方法可以很方便地跨window通信。由于它是一个很新的方法,所以在很旧和比较旧的浏览器中都无法使用,比如IE6和IE7,IE8已经支持这个方法了。
window.postMessage的使用方法比较简单,只有两个参数,第一个参数是要传输的消息,第二个参数是接收消息的域,可以用“×”来表示所有的域。发送消息的代码如下:
var o = document.getElementsByTagName('iframe')[0];
o.contentWindow.postMessage('Hello world', 'http://b.example.org/');
接收消息页面的代码如下:
window.addEventListener('message', receiver, false);
function receiver(e) {
if (e.origin == 'http://example.com') {
if (e.data == 'Hello world') {
e.source.postMessage('Hello', e.origin);
} else {
alert(e.data);
}
}
}
注意这里的绑定事件方式只针对非IE浏览器,IE浏览器需要用attachEvent方式来绑定事件。在上面的代码里你可以决定是否要判断消息的来源,这里是从安全角度考虑,防止不安全的消息。
FIM (Fragment Identitier Messaging)
FIM (Fragment Identitier Messaging)的原理是基于父窗口可以对iframe进行URL读写,iframe也可以写父窗口的URL(注意,跨域时iframe是不可以读取父窗口的URL的,但可以修改父窗口的URL),URL有一部分被称 为frag,就是#号及其后面的字符,它一般用于浏览器锚点定位,Server端并不关心这部分,应该说HTTP请求过程中不会携带frag,所以这部分的修改不会产生HTTP请求,也就是页面不会刷新,但是会产生浏览器历史记录。FIM的原理就是改变URL的frag部分来进行双向通信。每个window通过改变其它window的location来发送消息,并通过监听自己的URL的变化来接收消息。这个方式的通信会造成一些不必要的浏览器历史记录,而且有些浏览器 不支持onhashchange事件,需要轮询来获知URL的改变,最后,URL在浏览器下有长度限制,这个制约了每次传送的数据量。
先说父窗口向iframe发送消息,代码如下:
var o = document.getElementById('iframe');
o.href = 'http://www.weakweb.com#name=boris';
这样我们就把值传到iframe里面了,下面就需要考虑iframe如何监听何时有消息传递过来。这里有两个方法:1,在iframe里使用setInterval()轮询来判断当前的iframe的URL是否发生了变化,缺点是轮询会产生性能消耗;2,在父窗口里改变iframe的大小来触发iframe的window.onresize事件,缺点是要改变iframe窗口的大小。当iframe发现有消息传送过来时就可以通过locaiton.hash来读取了。
iframe向父窗口发送消息
parent.location.href = 'http://www.company.com#height=100';
上面提过,跨域时iframe可以写父窗口的URL,但是不可以读取的,所以这里我们就通过frag的方式把消息传递到父窗口了,同样,父窗口也需要监听啥时候有消息传进来,这里只能用轮询的方式了。
对FIM的一点改进
当父窗口采用修改iframe窗口大小的方式告诉iframe有消息传递方式时,这种方式有一个非常明显的缺点,那就是iframe窗口的大小改变会严重影响用户体验。因此这里采用的代理机制来处理。
我们额外创建了代理iframe叫proxyIframe吧,proxyIframe和之前的contentIframe是同一个域的,同时proxyIframe是隐藏不可见的,这样我们先把消息传递到proxyIframe里,然后在由proxyIframe发送到contentIframe,因为这两个iframe是同域的,所以可以很方便的传递。这样做的好处是我们只修改proxyIframe的大小而不用修改contentIframe的大小,这样不会影响用户体验,缺点是比之前复杂了一些。
浏览器的URL长度是有限制的,尤其是IE,所以我们可以通过分段传输来解决这个问题。
示例代码
我写了一个测试代码,其中包含了三个页面,一个父页面和两个iframe页面,点击下载
一个如何在本地测试运行上面的示例代码的简单方法,在C:\Windows\System32\drivers\etc\hosts文件,在里面添加两个域名指向127.0.0.1,这样就可以测试跨域了。我的hosts文件如下:
127.0.0.1 a.com
127.0.0.1 b.com
- iframe跨域通信方法(转自http://www.2cto.com/kf/201211/166555.html)
- 实现多线程的两种方法(转自:http://www.2cto.com/kf/201507/423032.html)
- argparse解析器 转自http://www.2cto.com/kf/201208/149418.html
- http://www.2cto.com/kf/201112/115476.html
- http://www.2cto.com/kf/201205/131945.html
- http://www.2cto.com/kf/201402/280576.html
- http://www.2cto.com/kf/201410/344061.html
- http://www.2cto.com/kf/201311/255432.html
- ASP.NET MVC HtmlHelper用法大全(转:http://www.2cto.com/kf/201105/90985.html)
- android ContentResolver详解 http://www.2cto.com/kf/201207/144022.html
- Android开发之MdiaPlayer详解 http://www.2cto.com/kf/201408/325309.html
- urllib2库 http://www.2cto.com/kf/201208/145070.html
- 使用HTTP协议访问网络 原网址https://www.2cto.com/kf/201701/552932.html
- Java生成二维码,转载!感觉不错Mark下(出处:http://www.2cto.com/kf/201108/98471.html)
- Java RandomAccessFile的使用(转载的文章,出处http://www.2cto.com/kf/201208/149816.html)
- $()和${}和$(())和(())///转自http://www.2cto.com/os/201308/239136.html
- 留作笔记,原文链接:https://www.2cto.com/kf/201607/529682.html
- http://www.2cto.com/database/201408/327315.html
- 数据结构之线性表5双链表
- swift_将UIDatePicker获取到的时间传到下一个页面出现相差几个小时的问题
- 编程之美:从无头单链表中删除节点,讨论
- Android实现推送方式解决方案
- [c.y.j]springmvc-mybatis[转]
- iframe跨域通信方法(转自http://www.2cto.com/kf/201211/166555.html)
- base64的js实现
- 变种二分查找
- 这博客已清理
- TCP/IP详解--TCP/IP连接各个状态转换分析
- web框架知识点链接整理
- Cloudera Manager分析
- 关于使用actionBar的一些问题
- 【Objective-C】集合类(NSArray, NSSet, NSOrderedSet 和 NSDictionary)