zoukankan      html  css  js  c++  java
  • postMessage跨源通信

     

    参考:https://www.cnblogs.com/dolphinX/p/3464056.html

    https://www.cnblogs.com/flora-dn/p/9019252.html

    一、跨源通信概述

    源:协议、端口号(https默认值433)、主机域名(document.domain)
    作用:向目标窗口派发MessageEvent消息(四个属性)
    兼容参考

    MessageEvent四个属性:
    1.message(类型)
    2.data(window.postMessage的第一个参数)
    3.origin(调用postMessage时页面的当前状态)
    4.source(调用postMessage的窗口信息)

    二、postMessage语法:

    otherWindow.postMessage(message, targetOrigin, [transfer]);

    otherWindow: 其他窗口(目标窗口)的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames
    (如父窗口向内嵌的iframe窗口发送信息)
    message :信息内容,低版本浏览器只支持字符串,高版本可以各种数据都行
    targetOrigin :目标窗口的源,可以是字符串*表示无限制,或URI,需要协议端口号和主机都匹配才会发送
    transfer:参考MDN

    三、接收postMessage发送的信息MessageEvent

    window.addEventListener("message", function(MessageEvent){
      var origin = event.origin || event.originalEvent.origin; 
      ....
      }, false);

    四、demo--利用iframe嵌套父子窗口通信

    父窗口:

    <!--我是父窗口-->  
    <div class="parent" >
          <iframe src="子窗口链接" id="iframe"></iframe>
    </div>
    <script>
    //监听子窗口信息
     window.addEventListener('message',function(event){
       ...
       })
    //父窗口给子窗口发消息,
    document.getElementByID('iframe').contentWindow.postMessage(msg,'子窗口源');
       
    </script>

    子窗口

    <!--我是子窗口-->  
    <div class="child"></div>
    <script>
    //子窗口给父窗口发消息
    try {//放到trycatch里面,解决有些手机卡住报错问题
      window.top.postMessage(msg,'父窗口源');
          //嵌套一层使用window.top(parent),多层window.frameElement
          //使用top而不是window,top指向iframe最顶层窗口
      } catch (error) {
    
    }
    
    //监听父窗口信息
     window.addEventListener('message',function(event){
       ...
       })
    </script>

    注意:

    父窗口给子窗口发信息,需要用iframe的contentWindow属性作为调用主体
    子窗口给父窗口发的信息需要使用window.top,多层iframe使用window.frameElement

    postMessage()可以解决的问题:

    1.页面和其打开的新窗口的数据传递

    2.多窗口之间消息传递

    3.页面与嵌套的iframe消息传递

    4.上面三个问题的跨域数据传递

    postMessage()

    这些问题都有一些解决办法,但html5引入的message的API可以更方便、有效、安全的解决这些难题。postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。

    postMessage(data,origin)方法接受两个参数

     1.data:要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果。

    2.origin:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以建参数设置为"*",这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

    http://test.com/index.html

    复制代码
    <div style="200px; float:left; margin-right:200px;border:solid 1px #333;">
            <div id="color">Frame Color</div>
        </div>
        <div>
            <iframe id="child" src="http://lsLib.com/lsLib.html"></iframe>
        </div>
    复制代码

    我们可以在http://test.com/index.html通过postMessage()方法向跨域的iframe页面http://lsLib.com/lsLib.html传递消息

    window.onload=function(){
                window.frames[0].postMessage('getcolor','http://lslib.com');
            }

    接收消息

    test.com上面的页面向lslib.com发送了消息,那么在lslib.com页面上如何接收消息呢,监听window的message事件就可以

    http://lslib.com/lslib.html

    window.addEventListener('message',function(e){
                    if(e.source!=window.parent) return;
                    var color=container.style.backgroundColor;
                    window.parent.postMessage(color,'*');
                },false);

    这样我们就可以接收任何窗口传递来的消息了,为了安全起见,我们利用这时候的MessageEvent对象判断了一下消息源,MessageEvent是一个这样的东东

    有几个重要属性

    1. data:顾名思义,是传递来的message
    2. source:发送消息的窗口对象
    3. origin:发送消息窗口的源(协议+主机+端口号)

    这样就可以接收跨域的消息了,我们还可以发送消息回去,方法类似

    简单的demo

    在这个例子中,左边的div会根据右边iframe内div颜色变化而变化

       

    http://test.com/index.html
    http://lslib.com/lslib.html

    在例子中页面加载的时候主页面向iframe发送’getColor‘ 请求(参数没实际用处)

    window.onload=function(){
                window.frames[0].postMessage('getcolor','http://lslib.com');
            }

    iframe接收消息,并把当前颜色发送给主页面呢

    window.addEventListener('message',function(e){
                    if(e.source!=window.parent) return;
                    var color=container.style.backgroundColor;
                    window.parent.postMessage(color,'*');
                },false);

    主页面接收消息,更改自己div颜色

    window.addEventListener('message',function(e){
                var color=e.data;
                document.getElementById('color').style.backgroundColor=color;
            },false);

    当点击iframe事触发其变色方法,把最新颜色发送给主页面

    复制代码
    function changeColor () {            
                    var color=container.style.backgroundColor;
                    if(color=='rgb(204, 102, 0)'){
                        color='rgb(204, 204, 0)';
                    }else{
                        color='rgb(204,102,0)';
                    }
                    container.style.backgroundColor=color;
                    window.parent.postMessage(color,'*');
                }
    复制代码

    主页面还是利用刚才监听message事件的程序处理自身变色

    window.addEventListener('message',function(e){
                var color=e.data;
                document.getElementById('color').style.backgroundColor=color;
            },false);

    最后

    很简单的用法却解决了大问题,据说Facebook已经在使用了,而且这也是html5另一个API——web workers传递消息的方法,那么它的浏览器兼容性怎么样呢?所谓浏览器兼容性几乎变成了IE几开始支持的问题了。。。不过好消息是跟localStorage一样,IE8+都支持了,只不过有些浏览器的低版本(比如FireFox4.0)并不支持window.onmessage=function(){}这种写法,所以我么最好使用事件绑定的写法,为了兼容IE,也要判断是否支持addEventListener。

  • 相关阅读:
    「酷客多」关注:马化腾公开演讲,透露2017年春节前会推出“小程序”
    微信小程序购物商城系统开发系列-目录结构
    微信小程序购物商城系统开发系列-工具篇
    上海闪酷成为京东商城第一批独立软件开发商(ISV)
    【FFMPEG】关于硬解码和软解码
    Git 别名配置
    【Linux】扩展阿里云数据盘分区和文件系统
    Python实现MQTT接收订阅数据
    【Linux】Devops的一些运维工具
    【Linux】YUM Repositories for CentOS, RHEL & Fedora Systems
  • 原文地址:https://www.cnblogs.com/zyx-blog/p/9360467.html
Copyright © 2011-2022 走看看