跨域之三:降域 和 postMessage

本节内容:实现跨域常用的两种方式 —— 降域 和 postMessage

零:跨域报错展示

在非同源情况下,操作 ifream 引入的元素时,浏览器会阻止这一操作,并且报错如下:


跨域报错 —— ifream
  • 本节会做演练,所以首先修改 hosts 文件,本节演练 hosts 文件增添内容为:
127.0.0.1 localhost
127.0.0.1 a.yang.com
127.0.0.1 b.yang.com
127.0.0.1 yang.com
127.0.0.1 a.com
127.0.0.1 b.com

一、降域

  • 何为降域?

降域仍是解决跨域问题的一种方案,通过双向设置 document.domain 的值,解决主域名下的跨域问题。

  • 降域的原理
  • 比如,有两个二级域名:a.yang.com 和 b.yang.com,可通过设定 document.domain 的值为主域名:yang.com 的方式,突破浏览器的同源策略限制,来获取和操作对方的元素

  • 这就好比,小 A 和小 B,手里拿着城主的令牌,通过哨卡时才能畅行无阻,否则哨卡不让过

  • 这也就决定了,降域具有很大的局限性,适用范围较小,适合在同一主域名下使用;需要有降的空间,方可使用降域方式

  • 降域的使用
  • A 页面域为:a.yang.com

  • B 页面域为:b.yang.com

  • A 和 B 两页面都需加入该行代码:document.domain = 'yang.com'; ,‘yang.com 是 a.yang.com 和 b.yang.com 的主域名

  • 降域演练

自己动手,丰衣足食。我来手动演练一番。

  • 演练说明
    1)页面的说明:
    A 页面的域为 a.yang.com;A 页面拥有两个元素 input 输入框、ifream,ifream引入 B 页面资源;
    B 页面的域为 b.yang.com;B 页面拥有一个元素 input 输入框
    2)实现的功能:在任意 input 输入框中输入值时,另外一个 input 输入框同步显示输入的值

  • 搭建 web 服务器的工具:server-mock
    A 页面代码 a.yang.com

var input = document.querySelector('.main input');
input.addEventListener('input', function () {
        console.log('window:' + this.value);
        window.frames[0].document.querySelector('input').value = this.value;
});
document.domain = 'yang.com';

B 页面代码 b.yang.com

    var input = document.querySelector('input');
    input.addEventListener('input', function () {
        console.log('iframe:'+ this.value);
        window.parent.document.querySelector('input').value = this.value;
    });
    document.domain = 'yang.com';

1)同源情况下:window.frames[0].document.querySelector('input') 可取到 ifream 中的 input 元素
2)非同源情况下:因为同源策略的限制,无法取到相应元素,会报错

二、postMessage

因为降域的局限性比较大,只能使用到有降域空间的域名上,那么当两个主域名完全不同时,应该如何处理呢?来看看新方法 postMessage。

  • postMessage 原理
  • postMessage 是 HTML5 中新增方法,可实现跨域通信;

  • postMessage 并不是向服务器读写资源,只是向外发送消息而已;可以把它当做使用手机发送短信消息,仅此而已。

  • 也就是:A 页面向 B 页面发送了一条消息,B 页面会接受到该消息,如果 B 页面需要该消息,则监听 message;否则无需关心该消息

  • postMessage 的使用
  • 发送方:为目标元素添加事件处理程序,监听事件类型

  • 接收方:为 window 添加事件处理程序,事件类型为 messag

  • postMessage 的演练

自己动手,丰衣足食。我来手动演练一番。

  • 演练说明
    1)页面的说明:
    A 页面的域为 a.com;A 页面拥有两个元素 input 输入框、ifream,ifream引入 B 页面资源;
    B 页面的域为 b.com;B 页面拥有一个元素 input 输入框
    2)实现的功能:在任意 input 输入框中输入值时,另外一个 input 输入框同步显示输入的值

  • 搭建 web 服务器的工具:server-mock
    A 页面代码 a.com

        var input = document.querySelector('.main input');
        input.addEventListener('input', function () {
            console.log('window:' + this.value);
            window.frames[0].postMessage(this.value, '*');
        });

        window.addEventListener('message', function (e) {
            console.log('window:'+ e.data);
            input.value = e.data;
        })

B 页面代码 b.com

    var input = document.querySelector('input');
    input.addEventListener('input', function () {
        console.log('iframe:'+ this.value);
        window.parent.postMessage(this.value, 'http://a.com:8080');
    });

    window.addEventListener('message', function (e) {
        console.log('ifream:'+ e.data);
        input.value = e.data;
    })
  • postMessage 的注意点
  • 这样就解除了降域的限制,可以将 postMessage 应用到各个不同的域之间,实现跨域访问。该方式比较安全,因为对方并不能直接操控我方资源,仅仅是发了一条消息,相当于指令,而最终操作权限仍在自己手中
  • 虽然解决了降域的限制,但是:postMessage 是 window 的一个方法,话句话说:它的弱点是只能向 window 窗口发送消息。所以使用时至少要有一个 window 才行,postMessage 不可以向其他域名发送消息。

最后:降域和 postMessage 都是小众的降域方式,并不是经常使用,若有需求可按需选择

本文章著作权归饥人谷和本人所有,转载须说明来源!

你可能感兴趣的:(跨域之三:降域 和 postMessage)