window.postMessage() 方法可以安全地实现跨域通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https),端口号(443为https的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。

一、安装live-server

要想实现跨窗口通信,必须要在服务器上运行,直接用浏览器打开HTML文件只能处理单个文件,窗口之间无法通信。

  1. npm install -g live-server

使用命令live-server进行启动。

安装live-server,在任意位置启动服务器。

在服务器中启动之后,会看见文档中多了一个script标签。这段代码是由live-server插入的。当运行在后台的live-server检测到文件变化,就会通过websockt向网页发送“reload”消息,从而可以实现浏览器中的网页总是实时的响应文件的变更。

  1. // <![CDATA[ <-- For SVG support
  2. if ('WebSocket' in window) {
  3. (function() {
  4. function refreshCSS() {
  5. var sheets = [].slice.call(document.getElementsByTagName("link"));
  6. var head = document.getElementsByTagName("head")[0];
  7. for (var i = 0; i < sheets.length; ++i) {
  8. var elem = sheets[i];
  9. head.removeChild(elem);
  10. var rel = elem.rel;
  11. if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") {
  12. var url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, '');
  13. elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
  14. }
  15. head.appendChild(elem);
  16. }
  17. }
  18. var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
  19. var address = protocol + window.location.host + window.location.pathname + '/ws';
  20. var socket = new WebSocket(address);
  21. socket.onmessage = function(msg) {
  22. if (msg.data == 'reload') window.location.reload();
  23. else if (msg.data == 'refreshcss') refreshCSS();
  24. };
  25. console.log('Live reload enabled.');
  26. })();
  27. }
  28. // ]]>

二、基础知识

MessageEvent有以下几个属性:

  • data:从其他window中传递过来的对象
  • origin:调用 postMessage 时消息发送方窗口的 origin
  • source:对发送消息的窗口对象的引用; 您可以使用此来在具有不同origin的两个窗口之间建立双向通信。

在发送数据窗口执行:otherWindow.postMessage(msg,origin)

  • otherWindow:表示接受数据的窗口的window对象,包括iframe的子窗口和通过window.open打开的新窗口。
  • msg表示要发送的数据,包扩字符串和对象(ie9以下不支持,可以利用字符串和json互换)。
  • origin表示接收的域名。

三、最简单的一个demo

父窗口打开一个子窗口,然后询问子窗口:“吃饭了吗”,子窗口回复父窗口:“吃了”

father.html

  1. <html>
  2. <body>
  3. </body>
  4. <script>
  5. window.addEventListener("message", function(e) {
  6. document.querySelector("body").appendChild(document.createTextNode('son say: ' + e.data))
  7. })
  8. var son = window.open("son.html")
  9. son.onload = function() {//必须得要等到儿子加载完成才可以说话
  10. son.postMessage("吃饭了吗", location.href)
  11. }
  12. </script>
  13. </html>

son.html

  1. <html>
  2. <body>
  3. </body>
  4. <script>
  5. window.addEventListener("message", function() {
  6. console.log(event)
  7. document.querySelector("body").appendChild(document.createTextNode("father say: " + event.data))
  8. event.source.postMessage("吃了", event.origin)
  9. })
  10. </script>
  11. </html>

四、一个网页聊天系统

father.html

  1. <html>
  2. <head>
  3. <style>
  4. textarea,
  5. input {
  6. width: 80%;
  7. font-size: 20px;
  8. font-family: "Consolas";
  9. }
  10. textarea {
  11. height: 80%;
  12. }
  13. input {
  14. height: 10%;
  15. }
  16. </style>
  17. </head>
  18. <body>
  19. <div style="text-align:center">
  20. <textarea readonly></textarea>
  21. <input type="text" style="margin-top:10px" onkeydown="keydown()">
  22. </div>
  23. </body>
  24. <script>
  25. function $(sel) {
  26. return document.querySelector(sel)
  27. }
  28. window.addEventListener("message", function() {
  29. $("textarea").value += "\nson say: " + event.data
  30. })
  31. var son = window.open("myson.html")
  32. function keydown() { //这里不需要传递参数,直接使用event就可以
  33. if (event.keyCode == 13) {
  34. son.postMessage($("input").value, location.href)
  35. $("textarea").value += "\n我说:" + $("input").value
  36. $("input").value = ""
  37. event.preventDefault
  38. }
  39. }
  40. </script>
  41. </html>

myson.html

  1. <html>
  2. <head>
  3. <style>
  4. textarea,
  5. input {
  6. width: 80%;
  7. font-size: 20px;
  8. font-family: "Consolas";
  9. }
  10. textarea {
  11. height: 80%;
  12. }
  13. input {
  14. height: 10%;
  15. }
  16. </style>
  17. </head>
  18. <body>
  19. <div style="text-align:center">
  20. <textarea readonly></textarea>
  21. <input type="text" style="margin-top:10px" onkeydown="keydown()">
  22. </div>
  23. </body>
  24. <script>
  25. var father = null
  26. window.addEventListener("message", function() {
  27. $("textarea").value += "\nfather say: " + event.data
  28. if (father == null) {
  29. father = {
  30. source: event.source,
  31. origin: event.origin
  32. }
  33. }
  34. })
  35. function $(sel) {
  36. return document.querySelector(sel)
  37. }
  38. function keydown() { //这里不需要传递参数,直接使用event就可以
  39. if (event.keyCode == 13) {
  40. father.source.postMessage($("input").value, location.href)
  41. $("textarea").value += "\n我说:" + $("input").value
  42. $("input").value = ""
  43. event.preventDefault
  44. }
  45. }
  46. </script>
  47. </html>

五、最后一个demo

  1. <html>
  2. <head>
  3. <meta charset="UTF-8">
  4. </head>
  5. <body>
  6. <input type="button" value="Open Window" onclick="openWin()" />
  7. </body>
  8. <script>
  9. window.addEventListener("message", function(evt) {
  10. var ele = document.createElement("pre")
  11. ele.innerText = "son say:" + JSON.stringify(evt.data)
  12. document.querySelector("body").appendChild(ele)
  13. })
  14. var popupwin = window.open("son.html");
  15. //onload只能执行一次,也就是如果子窗口有onload事件,可能会覆盖。
  16. popupwin.onload = function(e) {
  17. var params = "天下大势为我所控"
  18. var origin = location.href
  19. popupwin.postMessage(params, origin);
  20. }
  21. popupwin.onunload = function(e) {
  22. var ele = document.createElement("h1")
  23. ele.innerText = "儿子最后说:" + popupwin.returnValue
  24. document.querySelector("body").appendChild(ele)
  25. }
  26. </script>
  27. </html>

son.html

  1. <html>
  2. <head>
  3. <title>popup window</title>
  4. </head>
  5. <body>
  6. <button onclick="closeWin()">点我返回</button>
  7. <div id="show"></div>
  8. </body>
  9. <script>
  10. function closeWin() {
  11. window.returnValue = "这是返回值";
  12. window.close();
  13. }
  14. //HTML DOM fully loaded, and fired window.onload later.
  15. document.onreadystatechange = function() {
  16. if (document.readyState === 'complete') {
  17. window.addEventListener('message', function(event) {
  18. document.querySelector("#show").appendChild(document.createTextNode("father say:" + e.data))
  19. event.source.postMessage("what's the fuck", event.origin)
  20. });
  21. }
  22. };
  23. </script>
  24. </html>

六、安全问题

如果您不希望从其他网站接收message,请不要为message事件添加任何事件侦听器。

如果您确实希望从其他网站接收message,请始终使用origin和source属性验证发件人的身份。

当您使用postMessage将数据发送到其他窗口时,始终指定精确的目标origin,而不是*。

参考资料

https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage

window.postMessage实现网页间通信的更多相关文章

  1. JavaScript 跨域:window.postMessage 实现跨域通信

    JavaScript 跨域方式实现方式有很多,之前,一篇文章中提到了 JSONP 形式实现跨域.本文将介绍 HTML5 新增的 api 实现跨域:window.postMessage . 1 othe ...

  2. 利用HTML5的window.postMessage实现跨域通信

    详见: http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp77   HTML5的window.postMessage简述 postM ...

  3. window.postMessage跨文档通信

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

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

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

  5. 用HTML5里的window.postMessage在两个网页间传递数据

    说明 window.postMessage()方法可以安全地实现Window对象之间的跨域通信.例如,在一个页面和它生成的弹出窗口之间,或者是页面和嵌入其中的iframe之间. 通常情况下,不同页面上 ...

  6. 跨域通信--Window.postMessage()

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

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

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

  8. HTML5之worker开启JS多线程模式及window.postMessage跨域

    worker概述 worker基本使用 window下的postMessage worker多线程的应用 一.worker概述 web worker实际上是开启js异步执行的一种方式.在html5之前 ...

  9. 系统间通信(9)——通信管理与RMI 下篇

    接上文<架构设计:系统间通信(8)--通信管理与RMI 上篇>.之前说过,JDK中的RMI框架在JDK1.1.JDK1.2.JDK1.5.JDK1.6+几个版本中做了较大的调整.以下我们讨 ...

随机推荐

  1. 混沌数学之Baker模型

    相关DEMO参见:混沌数学之离散点集图形DEMO 相关代码: // http://wenku.baidu.com/view/ac9b57ea172ded630b1cb65b.html class Ba ...

  2. 【转载】如果快速开发APP&创业

    先贴原文所在个人博客: http://uikoo9.com/ 今天看了一些这个人的文章,还是有一定见解的,比如下面这篇 <如何快速开发出一个高质量的APP——创业谈> http://uik ...

  3. C#中图片透明【转】

    C#中图片透明 /// <summary> /// 处理图片透明操作 /// </summary> /// <param name="srcImage" ...

  4. [Backbone]5. Model & View, toggle between Models and Views -- 2

    Dr. Goodparts is pretty flaky and has been cancelling a lot of appointments lately. He's asked for a ...

  5. 2. Using 'dp' instead of 'px' to set text size

    android:textSize="45px"  ==> android:textSize="45dp" 因为Android Phone的手机分辨率各不相 ...

  6. 在Lotus Notes设置邮件转发

    Notes里面设置邮件转发,一种是创建一个Agent代理,但这种方式有弊端,就是邮件标题缺失,这个比较别扭.这里就不推荐了. 另一种方法是创建Rule规则,这种方式完美.具体方法如下: 1.点Tool ...

  7. Power Network (poj 1459 网络流)

    Language: Default Power Network Time Limit: 2000MS   Memory Limit: 32768K Total Submissions: 23407   ...

  8. iOS中ActionSheet和Alert的区别

    首先,样子长得就不一样 看下图:

  9. ubuntu 软件包管理工具 dpkg,apt-get,aptitude 区别

    ubuntu 软件包管理工具 dpkg,apt-get,aptitude 区别 一:dpkg dpkg 是一种比较低层的软件包安装管理工具,在安装时,不会安装软件包的依赖关系:只能安装所要求的软件包: ...

  10. 微信小程序 - 使用npm(第三方包)

    使用示例: 1. 开启“使用npm模块” 2. 新建 node_modules 文件夹 3. cd到新建 node_modules 所在的目录(非node_modules文件夹内) npm insta ...