javascript 跨越解决方案

同源策略简介
如果两个页面的协议、端口(如果指明了的话)和主机名都相同则两个页面拥有相同的源。同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性。这个策略可以追溯到 Netscape Navigator 2.0。
但很多时候两个不同域的页面之间需要进行通信,这就产生了跨域通信的问题了,关于跨域的文章非常多,可以参考10种方式实现跨域资源的共享,下面和大家分享一下我们项目中是如何进行双向跨域通信的,工大家参考。

解决方案

对 于双向跨域通信来说,选择的方案也不是很多,综合各种因素,我们选择FIM + window.postMessage的组合方式来解决跨域通信问题。因为这两种方式各有优缺点,window.postMessage,使用非常简单, 但是由于是个比较新的方法,IE6和IE7等老式浏览器不支持。FIM方法支持所有的浏览器,但比较繁琐,而且容易产生浏览记录,因此如果浏览器支持 window.postMessage就采用window.postMessage,否则就采用FIM技术。

window.postMessage解决方案

window.postMessage是HTML5定义的一个很新的方法,这个方法可以很方便地跨window通信。由于它是一个很新的方法,所以在很旧和比较旧的浏览器中都无法使用,比如IE6和IE7,IE8已经支持这个方法了。
window.postMessage的使用方法比较简单,只有两个参数,第一个参数是要传输的消息,第二个参数是接收消息的域,可以用“×”来表示所有的域。发送消息的代码如下:

双击代码全选

1

<span style="line-height:22px;font-family:arial, helvetica, sans-serif;background-color:#FFFFFF;" class="Apple-style-span">  var o = document.getElementsByTagName('iframe')[0];  o.contentWindow.postMessage('Hello world', 'http://b.example.org/');</span>

 

接收消息页面的代码如下:

双击代码全选

1

<span style="line-height:22px;font-family:arial, helvetica, sans-serif;background-color:#FFFFFF;" class="Apple-style-span">  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);      }    }  }</span>

 

注意这里的绑定事件方式只针对非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发送消息,代码如下:

双击代码全选

1

<span style="line-height:22px;font-family:arial, helvetica, sans-serif;background-color:#FFFFFF;" class="Apple-style-span">  var o = document.getElementById('iframe');  o.href = 'http://www.weakweb.com#name=boris';</span>

 

这 样我们就把值传到iframe里面了,下面就需要考虑iframe如何监听何时有消息传递过来。这里有两个方法:1,在iframe里使用 setInterval()轮询来判断当前的iframe的URL是否发生了变化,缺点是轮询会产生性能消耗;2,在父窗口里改变iframe的大小来触 发iframe的window.onresize事件,缺点是要改变iframe窗口的大小。当iframe发现有消息传送过来时就可以通过 locaiton.hash来读取了。