跨域消息传递

整理了一些跨越的几个方法,postMessage 、修改window.domain、修改window.name、修改hash

好久之前就想好好看下有关跨域的问题了,自己遇到过几次,然后面试的时候也被问道过几次,好好系统的学下,了解下,强烈建议还是自己亲手动着去写下demo,纸上得来终觉浅,多多实践才是真,貌似有很多的方法,我就列举一些我自己知道的办法,貌似现在网上也有一些成熟的库来实现这个问题

##PostMessage()方法##
说明:postMessage(message, targetOrigin);

测试方法:对于window用户,去找到host或者用浏览器的插件去添加
child.com 127.0.0.1
parent.com 127.0.0.1
然后我用的是webstorm和myeclipse,分别把两个代码放到了两个域下面,分别是http://parent.com:63342和http://child.com/
对于主页面附上代码如下

<body>
<h2>I'm father body</h2>
<div>
    <h4>message from child</h4>
    <div id="infoList"></div>
</div>
<h4>input message to child</h4>
<input type="text" id="message">
<button onclick="sendMessage()">send</button>
<div style="clear:both"></div>
<br />
<br>
<iframe id="ifb" name="b"  src="http://child.com/demo/b.htm" width="500px" height="300px"></iframe>
</body>
<script>
   var _messageList  = document.getElementById("infoList");
   var sendMessage = function(){
        var _parent = document.getElementById("ifb");
        var _target = "http://child.com:80";
        var _messageContent= document.getElementById("message").value;
        _parent.contentWindow.postMessage(_messageContent,_target);
    };

   window.addEventListener('message',function(e){
       if(e.origin == "http://parent.com/"){
           var _tmp = document.createElement("div");
           _tmp.textContent = e.data;
           _messageList.appendChild(_tmp);
       }
   },false);
</script>

对于主页面下的iframe的代码如下

<body>
<h2>I'M modal B</h2>
<div class="left">
    <h4>message from father</h4>
    <div id="infoList"></div>
</div>
<div class="right">
    <h4>send message to father</h4>
    <input type="text" id="message">
    <button onclick="sendMessage()">send</button>
</div>
</body>
<script type="text/javascript">
    var _messageList  = document.getElementById("infoList");
    window.addEventListener('message',function(e){
        if(e.origin == "http://parent.com:63342"){
            console.log(e.data);
            var _tmp = document.createElement("div");
            _tmp.textContent = e.data;
            _messageList.appendChild(_tmp);
        }
    },false);

    var sendMessage =function (){
        var _parent = window.parent;
        var _target = "http://parent.com:63342";
        var _messageContent= document.getElementById("message").value;
        _parent.postMessage(_messageContent,_target);
    };
</script>

这里再提几点需要注意的地方:

  1. 在页面的捕获message事件的时候,里面的e.origin必须要具体到端口,自己在测试的时候因为没写端口,就没有得到相应;
  2. 页面中的sendMessage需要等到里面的iframe加载完毕才可以执行,关于这点,初步的判断是iframe的加载是异步的,所以当iframe还没加载完毕,下面就运行postmessage是不行的

总结:实现还是很方便的,不过是html5中提供的api,对于旧的貌似就不适用了

##document.domain+iframe##
这个方法主要针对的是那些主域相同,而子域不同的情况的那些例子,具体的比如
www.parent.com和parent.com就是属于这样的情况,老样子,把host的相关内容修改下
127.0.0.1 www.parent.com
127.0.0.1 parent.com
如果在没设置两个子域window.domain的情况下。直接在www.parent.com/a.htm下去访问parent.com/b.htm中的dom是不成功的,这时只需要在iframe中的b.htm中添加上window.domain= “paren.com”,在a.htm中同样也这么设置一下,你就会发现两者可以互相访问了。不过这种情况适用的场合比较少,而且这个设置domain也不能随便设置。比如是www.parent.com设置成children.com这样是不可行的。

总结:有一些局限性,需要特定的场合下(主域相同)

##window.name##
具体的实现代码可可以见参考文章3,主要的做法就是下面几步

  1. 用一个iframe加载一个外域的页面
  2. 外链的页面来修改他所在的这个iframe中window的name的属性
  3. 主域中通过改变这个iframe中的window对象的location来指向一个跟他同域的代理页面。此时他边可以读取这个iframe中的window的name属性了。
  4. 最后最好在代理页面的结尾将这个iframe回收掉

##iframe+location.hash##
具体的实现也可以参考文章4,我大致就写下一点实现过程,主要的步骤如下:

  1. 在主域parent.com/a.htm下引入一个iframe的,指向一个外链children.com/b.htm,然后需要的参数可以通过一个定时器来不停的从hash中检测提取;
  2. 然后在b.htm中,添加一个iframe,指向一个同a.htm域的代理页面tmp.htm,有点跟前面的那个有点像,在指向的过程中,后面在添加一个hash的数值;
  3. 在tmp.htm中将自己所处的location.hash赋值给顶部父元素a.htm的location中去,此时,a.htm会检测到新的hash,即完成了从里面想外传递数据的过程

这个方法的弊端么很明显就是把一些数值直接在hash上显示了,要是在url自己手动进行了修改,那么他所读取的就是自己手动随便修改的数值

##jsonp##

一般的内容都会在浏览器中收到跨域访问的限制,但是有一个内容算是没有被受限的,就是标签script,这里面的资源不会受到跨域的限制,常见的经常我们会用一些cdn加速的东西来引入jquery这类的资源等等,所以可以通过这个方法来实现,之前在博客上也有一个整理过,我就直接附上链接好了jsonp处理跨域

##其他##
还有一些其他的方法,例如用flash来实现,因为不会,所以就不怎么提了,还有就是CORS(后台实现),这个需要后端在Access-Control-Allow-Origin进行一些设置。

相关推荐文章:

  1. Javascript跨域详解(1)
  2. JavaScript跨域详解(2)
  3. window.name实现的跨域数据传输
  4. JavaScript跨域总结与解决办法
  5. 前端解决跨域问题的8种方案

最后附上以上实现的demo,因为demo是后续补充的,所以搭的时候是node+webstorm的组合

update 2014.8.11