http://iknowledge.wikispaces.com/HTML5+postMessage%E5%92%8C%E8%B7%A8%E5%9F%9F%E9%80%9A%E4%BF%A1
HTML5 postMessage和跨域通信
-
浏览器的同源策略
Jesse Ruderman对于同源策略的定义为:“同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性”[1] 。从安全性的角度来说,同源策略认为任何来自其他站点动态装载的内容,其安全性都是不可知的,所以对于浏览器来说,在要求动态内容时,只应该读取同源的HTTP应答和Cookies,而不能读取不同源的内容[2] [3] 。如果两个页面拥有相同的源,它们的协议、端口和主机名都相同,那么可以认为这两个页面是同源的,可以动态的读取对方的信息。
- 举个例子来说明同源问题:[4]
- 假设浏览器当前访问的页面是: http://www.google.com/image/logo.html
- + 动态读取: http://www.google.com/image/other.html
- # 同一域名,不同文件,可以读取
- + 动态读取: http://www.google.com/style/style.html, 可以执行
- # 同一域名,不同文件夹,可以读取
- + 动态读取: https://www.google.com/image/logo.html, 不可以执行
- # 同一域名,不同协议,不可以读取
- + 动态读取: http://www.google.com:5656/image/logo.html,不可以执行
- # 同一域名,不同端口,不可以读取
- + 动态读取: http://www.baidu.com/image/logo.html,不可以执行
- # 不同域名,不可以读取
- + 动态读取: http://80.12.122.24/logo.html,不可以执行
- # 域名与域名对应ip,不可以读取
- + 动态读取:http://video.google.com/logo.html,不可以执行
- # 主域相同,子域不同,不可以读取
- + 动态读取:http://google.com/logo.html,不可以执行
- # 同一域名,不同二级域名,不可以访问
-
跨域通信
如果WebApp需要从第三方的服务器获取数据,该如何避免同源策略的限制呢?
已经存在多种方案,客服同源策略的限制,他们包括:
+ 通过iframe实现跨域通信[5]
+ 通过JSONP实现跨域通信[6]
+ 通过设置Ajax通信代理
-
HTML5 postMessage() API
postMessage()是HTML5为了解决现存的跨域问题引入的一个新的API。同源策略的前提是假定任何来自其他站点动态装载的内容,其安全性都是不可知的。postMessage将安全问题的检查抛给了使用者本身,在W3C的官方文档中提到,用户应该在使用前自行确认跨域安全[7] 。
API: /* * @param message: 需要发送的信息 * @param targetOrigin: 希望发送到的域名 ('*'代表所有的域,'/'代表只发送给同域目标) */ window.postMessage(message,targetOrigin [, transfer])
同时在W3C的文档中提到,为了保证postMessage()发送的信息能够被接受到,那么接收端receive message listener的代码应该首先保证被加载和运行。
- 1. 一个页面里面加载了两个iframe,一个iframe向另一个发送信息
- +发送端代码:
-
setTimeout(function(){ window.parent.frames[1].postMessage('Send message: [Message]','*'); },1000);
- +接受端代码:
-
var onMessageReceived = function(e){ var msg = e.data; alert('Received message: '+msg); } if (typeof window.addEventListener != 'undefined') { window.addEventListener('message', onMessageReceived, false); }else if (typeof window.attachEvent != 'undefined') { window.attachEvent('onmessage', onMessageReceived); };
- 这里使用了setTimeout延迟1秒是为了保证接收端listener能够首先工作起来。
- [ Example (已经对js代码做了封装的例子) ]
- [ Example (未做封装,推荐学习使用) ]
- 2. 一个页面打开一个新的页面,当前页面将信息传递给新的页面
- 对于这个Usecase来说,具体传送接受的代码没有任何变化,变化的是postMessage的对象,具体请查看Example
- [ Example ]
- ^ [ JavaScript的同源策略 ]
- ^ [ 浏览器同源策略解释 ]
- ^ [ 同源策略 ]
- ^ [ 利用HTML5的window.postMessage实现跨域通信 ]
- ^ [ 通过iframe实现跨域通信 ]
- ^ [ 使用JSONP实现跨域通信 ]
- ^ [ W3C postmsg API ]