跨域-跨域文档消息传递(cross-document messaging XDM)

  跨文档消息传送(cross-document messaging),有时候也简称为XDM,指的是来自不同域的页面间传递消息。例如,www.w3cmm.com域中的一个页面与一个位于内嵌框架中的p2p.w3cmm.com域中的页面通信。在XDM机制出现之前,更稳妥地实现这种通信需要花很多功夫。XDM把这种机制规范化,让我们能既稳妥有简单地实现跨文档通信。

  XDM的核心是postMessage()方法。在HTML5规范中,除了XDM部分之外的其它部分也会提到这个方法名,但都是为了同一个目的:向另一个地方传递数据。对于XDM而言,“另一个地方”指的是包含在当前页面中的<iframe>元素,或者由当前页面弹出的窗口。

  postMessage()方法接收两个参数:一条消息和一个表示消息接收方来自哪个域的字符串。第二个参数对保障安全通信非常重要,可以防止浏览器把消息发送到不安全的地方。下面来看个例子:

这是主页面home.html;运行的时候需要在eclipse或者Myeclipse下运行:

[html]  view plain  copy
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4. <meta charset="utf-8">  
  5. <title>跨文档消息传输示例</title>  
  6. <script src="EventUtil.js"></script>  
  7. </head>  
  8. <body>  
  9. <iframe src="msg.html" width="400" height="400" onload="sendMsg();" id="iframe"></iframe>  
  10. <div id="div1">  
  11. </div>  
  12. <script type="text/javascript">  
  13. EventUtil.addHandler(window,"message",function(event){  
  14.       document.getElementById('div1').innerHTML='从event.origin='+event.origin+',那里来的消息event.data='+event.data;       
  15. });  
  16. //向id为iframe内嵌框架中发送一条消息  
  17. function sendMsg(){  
  18.     //获取框架中的window  
  19.     var iframeWindow = document.getElementById("iframe").contentWindow;  
  20.     var information={"张三":10,"李四":20,"王五":30,"小明":40,"小白":50,"老五":60,"老周":67};  
  21.     var jsontext=JSON.stringify(information);  
  22.     setTimeout(function(){  
  23.     //iframe窗口加载完成,使用postMessage向iframe内发送消息  
  24.     //第一个参数为:消息内容  
  25.     //第二个参数为:接收消息的对象窗口url,一般与iframe的src一致  
  26.     iframeWindow.postMessage(jsontext,"http://localhost:8080/test/msg.html");},2000);  
  27. }  
  28. </script>  
  29. </body>  
  30. </html>  

  最后一行代码尝试向内嵌框架中发送一条消息,并指定框架中的文档必须来源于“http://localhost:8080/test/msg.html”域。如果来源匹配,消息会传递到内嵌框架中;否则,postMessage()什么也不做。这一限制可以避免窗口中的位置在你不知道的情况下发生改变。如果传给postMessage()的第二个参数是“*”,则表示可以把消息发送给来自任何域的文档,但我们不推荐这样做。

  接收到XDM消息时,会触发window对象的message事件。这个事件是以异步形式触发的,因此从发送消息到接受消息(触发接受窗口的message事件)可能要经过一段时间的延迟。触发message事件后,传递给onmessage处理程序的事件对象包含以下三方面的重要信息。

  data:作为postMessage()第一个参数传入的字符串数据。

  origin:发送消息的文档所在的域,例如“https://www.w3cmm.com”。

  source:发送消息的文档的window对象的代理。这个代理对象主要用于在发送上一条消息的窗口中调用postMessage()方法。如果发送消息的窗口来自同一个域,那这个对象就是window。

  接受到消息后验证发送窗口的来源是至关重要的。就像给postMessage()方法指定第二个参数,以确保浏览器不会把消息发送给未知页面一样,在onmessage处理程序中检测消息来源可以确保传入的消息来自已知的页面。基本的检测模式如下例:msg.html是id为iframe内嵌框架中的页面。

[html]  view plain  copy
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4. <meta charset="utf-8">  
  5. <title>iframe内容</title>  
  6. <script src="EventUtil.js"></script>  
  7. <script type="text/javascript" >  
  8. EventUtil.addHandler(window,"message",function(event){  
  9.  if(event.origin=="http://localhost:8080"){//注意origin是发送消息的文档所在的域。  
  10.    //接收从e.origin发来的消息e.data  
  11.    var obj = JSON.parse(event.data);  
  12.    aHtml = [];  
  13.    for (var key in obj) {  
  14.       var age = obj[key], str = '';  
  15.       switch(true) {  
  16.         case age<=10:  
  17.              str = key + '小朋友今年' + age + '岁。';  
  18.              break;  
  19.         case age<=20:  
  20.              str = key + '年青人今年' + age + '岁。';  
  21.              break;  
  22.         case age<=30:  
  23.              str = key + '中年人今年' + age + '岁。';  
  24.              break;  
  25.         case age<=40:  
  26.              str = key + '壮汉今年' + age + '岁。';  
  27.              break;  
  28.         case age<=50:  
  29.              str = key + '猛男今年' + age + '岁。';  
  30.              break;  
  31.         case age<=60:  
  32.              str = key + '快退休了,今年' + age + '岁。';  
  33.              break;  
  34.         default:  
  35.              str = key + '老年人今年' + age + '岁。';  
  36.              break;  
  37.      }  
  38.      aHtml.push(str);  
  39.   }  
  40.   document.body.innerHTML = '从event.origin=' + event.origin + ',发来的消息event.data=<br />' + aHtml.join('<br />');   
  41.  }else{  
  42.    alert("不可信任的消息源");  
  43.  }  
  44.  setTimeout(function() {  
  45.    //event.source即主页面的window对象,使用它向主页面发送消息  
  46.    event.source.postMessage('已经收到', event.origin);  
  47.  },2000);  
  48.      
  49. });  
  50. </script>  
  51. </head>  
  52. <body>  
  53. <div id="div1">  
  54. </div>  
  55. </body>  
  56. </html>  

运行结果如下:

 

  还是要提醒大家,event.source大多数情况下只是window对象的代理,并非实际的window对象。换句话说,不能通过这个代理对象访问window对象的其它任何信息。记住,只通过这个代理调用postMessage()就好,这个方法永远不存在,永远可以调用。

  XDM还有一些怪异之处。首先,postMessage()第一个参数最早是作为“永远都是字符串”来实现的。但后来这个参数的定义改了,改成允许传入任何数据结构。可是,并非所有浏览器都实现了这一变化。为保险起见,使用postMessage()时,最好还是只传字符串。如果你想传入结构化的数据,最佳选择是先在要传入的数据上调用JSON.stringify(),通过postMessage()传入得到的字符串,然后再在onmessage事件处理程序中调用JSON.parse()。

  在通过内嵌框架加载其它域的内容时,使用XDM是非常方面的。因此,在混搭和社交网络应用中,这种传递消息的方法极为常用。有了XDM,包含<iframe>的页面可以确保自身不受恶意内容的侵扰,因为它只通过XDM为嵌入的框架通信。而XDM也可以来自相同域的页面间使用。

  支持XDM的浏览器有Opera、IE8+、Safari 4+、Firefox 3.5+、Chrome、Android版Webkit和iOS版Safari。更多有关XDM的小东东可以去XDM官方页面去学习参考。XDM的官方页面是http://dev.w3.org/html5/postmsg/。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值