XDM
cross-document messaging 类似于XSS的简称,故称为 XDM 而不是 CDM
某些时候 XDM 也能作为跨域的实现手段之一
与Jsonp 和 传统的 CORS 跨域方式不同
XDM通常用于不同域的页面之间传递消息
postMessage
postMessage() 方法作为 XDM 的核心被添加进了 HTML5 规范中
该方法的作用是:向当前页面的iframe或者弹出的窗口传递消息
该方法用于接收以下两个参数:
- 消息的内容
- 接收消息的域
通过第二个参数可以防止浏览器将信息发送到不安全的地方
使用方法如下:
// 支持XDM的浏览器也支持 iframe 的 contentWindow属性 let iframeWindow = document.getElementById("myframe").contentWindow; iframeWindow.postMessage("这里是消息","http://www.example.com");
上方的postMessage的第二个参数则用于指定接收消息的文档的源域
如果匹配,则将消息传入内嵌框架中,否则什么也不做
当然该参数也可以设置为"*" 表示所有域都可以接受消息
发送消息介绍完了,自然就需要接收传递的信息
当文档接收到 XDM消息时就会触发 window 对象的 message 事件
该事件是以异步形式触发的所以可能存在时延, 触发该事件后,该事件的事件对象(event)会包含以下信息:
- data: postMessage传入的第一个参数字符串数据
- origin: 发送消息文档的所在的域
- source: 发送消息文档的window对象的代理,用于在发送上一条消息的窗口中调用postMessage方法(即发送回执消息)
就像发送时指定消息接收的域一样,收到消息后验证消息的来源域也同样重要,以此保证消息来自已知的域
基本的验证如下:
window.onmessage = function(event){ // 确保消息来源于已知域 if(event.origin == "http://www.example.com"){ // 处理接收的数据 processMessage(evnet.data); // 可选,向来源窗口发送回执 event.source.postMessage("Received","http://example1.com"); } }
需要注意的是:
evnet.source 大多数情况下只是 window 对象的代理对象,也就是说并不是真正的 window 对象
所以不能通过该代理对象来访问原本 window 对象上的属性和值
XDM的一个怪异之处在于:
postMessage的第一个参数最早是作为永远都是字符串来实现的,但后来允许传入任何数据结构,但是为了保险起见最好还是只传入字符串,如果希望传入json数据最好使用 JSON.stringify() 来处理
圈起来上面的是要考的,在阿里面前端的时候被问到,当时是蒙逼且绝望的emm....
最后就是这种跨域的浏览器兼容情况了,话不多说直接上图,自己感受