2019独角兽企业重金招聘Python工程师标准>>> hot3.png

HTML5 跨域通信 API - window.postMessage

参考
MDN - Window.postMessage()

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

  • message 你要发送的信息(字符串和对象都可以)
  • targetOrigin 你要发送信息的目标域名
  • transfer 可选参数,具体啥意思还没做深入了解,也暂时都还没用到过。

MDN 介绍的 window.postMessage() 是针对在一个页面使用 window.open() 动态打开新的页面而进行的跨域通信,非常详细,Demo 也很实用,但是对我而言貌似还欠缺什么东西。

注意,在实现跨域通信是,必须首先先获得其他域的window窗体对象

Tips
在 var targetPage = window.open('http://target.com') 打开新页面之后需要等到 http://target.com 页面加载完成之后才能进行 postMessage 跨域通信,但是在跨域的情况下我们是无法对 targetPage 进行 onload 事件监听的,所以这里只能做 延迟 setTimeout 或者 定时 setInterval 处理。 同样的,在页面内嵌入 iframe 页面的情况下,我们也需要等到页面内的 iframe 加载完成之后进行 postMessage 跨域通信。

解决问题要从问题源头出发,我现在遇到的问题归根究底就是两个不同域名的页面如何进行通信?
浏览器的同源政策不允许跨域,然而 HTML5 API window.postMessage() 就是用来实现跨域通信的。
那么通信的原理是怎样的了?
如果有两个页面 PageA 和 PageB,PageA 页面内嵌入 iframe PageB,那么理论上是应该可以实现双向通信的。
其实非常简单,就是 PageA 通过 window.postMessage() 发送一个信息给 PageB,PageB 在 window 上添加一个事件监听绑定 message 事件可以接收到来自任何不同域名通过 postMessage 方法发送过来的信息,当 PageB 接收到 PageA 发送过来的信息时执行监听事件就 OK,在监听事件的 event 参数中包含了所有 message 事件接收到的相关数据。包括发送信息的内容 event.data,发送信息的域名 event.origin 等等。

同样的,在 PageA 内添加一个事件监听绑定 message 事件,在 PageB 内通过 postMessage 方法发送信息给 PageA 一样可以进行跨域通信。

Tips
我们可以通过 event.origin 来过滤掉来自其他未知站点发送过来的 message 事件信息,防止跨站攻击!

大概就是以上的思考,然后继续写 Demo...

干货代码PageA

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Page A</title>
</head>
<body><h1>This is Page A</h1><button id="openNewWindowBtn" type="button">Open New Window</button><button id="postMessageBtn" type="button">Post Message</button><p id="message"></p><iframe id="receiverIframe" src="http://192.168.198.157:3000/pageB.html" frameborder="1" width="800" height="500"></iframe><script>window.onload = function() {var receiver = document.getElementById('receiverIframe').contentWindow;var postBtn = document.getElementById('postMessageBtn');var openBtn = document.getElementById('openNewWindowBtn');var messageEle = document.getElementById('message');function sendMessage() {receiver.postMessage('Hello Page B.. This is page A.. You are my iframe', 'http://192.168.198.157:3000');}function openNewWindow() {var pageB = window.open('http://192.168.198.157:3000/pageB.html');setTimeout(function() {pageB.postMessage('Hello Page B.. This is Page A.. (form PageA window.open())', 'http://192.168.198.157:3000');}, 500)}function receiveMessage(event) {console.log(event);if (event.origin !== 'http://192.168.198.157:3000') return;messageEle.innerHTML = "Message Received: " + event.data;}postBtn.addEventListener('click', sendMessage, false);openBtn.addEventListener('click', openNewWindow, false);window.addEventListener('message', receiveMessage, false);}</script>
</body>
</html>

PageB

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Page B</title>
</head>
<body><h1>This is Page B</h1><button id="postMessageBtn" type="button">Post Message</button><p id="message"></p><script>window.onload = function() {var postBtn = document.getElementById('postMessageBtn')var messageEle = document.getElementById('message');function receiveMessage(event) {console.log(event);if (event.origin !== 'http://192.168.198.157:8000') return;messageEle.innerHTML = "Message Received: " + event.data;// 接收 PageA 的任何消息都自动回复并加上时间戳event.source.postMessage('Hello Page A.. This is page B.. (from PageB autoreply) timestamp = ' + new Date().getTime(), event.origin);}function sendMessage() {// 这里需要特别注意!!!// 直接打开 PageB (当前页面) 是无法向 PageA 发送跨域信息的!!!// 只有当 PageB (当前页面) 处于 PageA 页面内的 iframe 中的时候才能发送跨域信息 // 而且此处不能使用 window.postMessage()// 因为 PageB (当前页面) 是 PageA 页面内嵌入的 iframe// 此时 PageB 的 window 指向的是 PageA 内 iframe 框架内的 window// 而当前情况需要指向父级 window (即 top 或者 parent) 才能进行 postMessagetop.postMessage('Hello Page A.. This is page B..', 'http://192.168.198.157:8000');}postBtn.addEventListener('click', sendMessage, false);window.addEventListener('message', receiveMessage, false);}</script>
</body>
</html>

踩过的坑

PageB 需要特别注意的地方!!!
直接在浏览器中打开 PageB 页面是无法向 PageA 页面发送跨域信息的!!!

PageB 页面的 receiveMessage 方法自动回复了所有来自 PageA 页面的 postMessage 信息并且加上了时间戳。

为什么 PageB 页面内的 sendMessage 方法使用的是 top.postMessage() 发送跨域信息???

答案就在下面的结论中
Tips
如果不是使用 window.open() 打开的页面或者 iframe 嵌入的页面,就跟当前页面扯不上任何关系,是无法使用 window.postMessage() 进行跨域通信的!!!

描述的貌似不是很清楚,举个栗子:

如果你打开浏览器,输入一个页面地址 PageA,然后打开一个新的标签页,又输入一个页面地址 PageB,那么这两个页面是无论如何都不能使用 window.postMessage() 来进行跨域通信的,他们并没有任何血缘关系...

同样,打开浏览器,输入一个页面地址 PageA,然后通过 PageA 动态打开 PageB (当然,不是通过 PageA 内的 a 标签链接打开),或者 PageA 内嵌入了 iframe PageB,那么这个时候就厉害了,它两有血缘关系啦!PageB 这个时候是不是就相当于是 PageA 是崽崽?是因为有了 PageA,所以才有了 PageB 的出现。然后理所当然的,PageA 拥有了控制 PageB 的某些权限,其中就包括 window.postMessage()。

得出结论

window.postMessage() 中的 window 到底是什么呢?

A:始终是你要通信的目标页面的 window

PageA 页面内嵌入 iframe PageB 页面
PageA 页面向 PageB 页面发送跨域信息,window 为 PageB 页面的 window,即 iframe.contentWindow。

PageB 页面向 PageA 页面发送跨域信息,window 为 PageA 页面的 window,即 top 或者 parent。

PageA 页面内代码使用 window.open() 打开 PageB 页面
PageA 页面向 PageB 页面发送跨域信息,window 为 var pageB = window.open('http://192.168.197.157:3000/pageB.html') 中的变量 pageB。

PageB 页面无法主动给 PageA 页面发送跨域信息,必须先接收到 PageA 页面发送过来的 message 然后再通过 event.source 发送给 PageA,没错... 此时的 window 就是 event.source,即 PageA 的 window

最后最后

请无论如何在监听 message 事件的函数内对 event.origin 进行过滤,不然来自未知站点的 window.postMessage() 可以对你的站点为所欲为。

转载于:https://my.oschina.net/u/2369810/blog/746642

window.postMessage相关推荐

  1. window.postMessage跨文档通信

    window.postMessage 1.浏览器兼容情况:IE8+.chrome.firefox等较新浏览器都至此. 2.使用方法: a.otherWindow.postMessage( messag ...

  2. window.postMessage实现网页间通信

    window.postMessage() 方法可以安全地实现跨域通信.通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https),端口号(443为https的默认值),以 ...

  3. 使用window.postMessage实现跨域通信

    JavaScript由于同源策略的限制,跨域通信一直是棘手的问题.当然解决方案也有很多: document.domain+iframe的设置,应用于主域相同而子域不同: 利用iframe和locati ...

  4. window.postMessage 跨窗口,跨iframe javascript 通信

    同源通信 执行它们的页面位于具有相同的协议(http/https),端口(80/443),主机(通常为域名) 时,这两个脚本才能相互通信 大多数情况下,网站就是内部的域名,所以是同源通信,可以相互访问 ...

  5. H5跨域通信 - window.postMessage

    一.简介 window.postMessage is a method for safely enabling cross-origin communication. Normally, script ...

  6. ifrme嵌入外部页面,在外部页面调用本页面方法,window.postMessage实现跨域通信

    项目场景:vue页面开发的系统要继承外部系统页面,并且在外部系统页面调用本系统的方法,这样来看的话肯定会存在跨域的问题,而且直接调用方法的话,也不太安全,后来了解到window.postMessage ...

  7. window.postMessage - 前端跨域通信

    window.postMessage - 前端跨域通信 window.postMessage() 语法 The dispatched event 安全问题 示例 注意 HTMLIFrameElemen ...

  8. vue中使用window.postMessage

    参考MDN: https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage 一.发送端 1.发送消息的基本语法 targetW ...

  9. DOM跨域的三种解决方案:document.domain、window.name、window.postMessage

    文章目录 同域访问 document.domain 相同二级域名之间的跨域 相同域名,不同端口之间的跨域 window.name window.postMessage 同域访问 浏览本篇文章之前,需要 ...

  10. [乐意黎转载]Window.postMessage() HTML5 跨域解决方案

    Hey,everybody~ 又是倒霉的跨域 T T , 有多少人死在了"说出你知道的跨域解决方案,越多越好?"这个面试问题上. 今天和大家说说,HTML5提供的一个跨域解决方案, ...

最新文章

  1. Java2021中级面试题
  2. javaScript中常见的几种报错类型
  3. activiti bpmn 安装不上_小猿圈之Eclipse安装Activiti插件(流程设计器)
  4. [蓝桥杯] 蚂蚁感冒
  5. php发卡8.0源码_素材资源解析平台PHP源码 V8.0运营版+会员功能+代理功能+卡密充值...
  6. python自动化入门操作文档,写得如此清晰明了,忍不住让人点赞
  7. 哈夫曼树(利用python实现)
  8. [Git]4.1 分支与合并
  9. Java:反射和注解从入门到放弃
  10. C# 合并多种格式文件为PDF
  11. 我对 SRE 的理解
  12. java 实现QQ自动登录(带验证码)
  13. 快手抖音短视频如何解析去除视频水印
  14. Geoserver入门操作系列之二:创建图层样式
  15. vue脚手架下载及使用
  16. java狼羊草过河_解决狼、羊、白菜过河问题的编程思路
  17. 高性能MySQL(一) 如何做到高扩展性
  18. 为html添加footbar,foobar2000界面组件添加设置方法
  19. 使用Pytorch实现简单的LSTM股票预测框架
  20. 高架桥隔音墙厂家价格@平衡生命

热门文章

  1. junit4同一时候測试多个測试类
  2. VC下关于debug和release的不同的讨论(收藏-转载)
  3. 搭建MHA时 yum 安装perl模块提示 baseurl 错误
  4. 监控服务器ssh登录,并发送报警邮件
  5. XMLHTTPRequest如何访问需要安全验证的网站
  6. c++中istream类型到bool类型的隐式转换
  7. Jmeter中Websocket协议支持包的使用 (转)
  8. SQL注入原理解说,非常不错!
  9. 学习wordpress模板制作第一天 函数bloginfo
  10. DB2 9 根本(730 检修)认证指南,第 6 局部: 数据并发性(2)