一、跨文档消息通信
出于安全方面的看的考虑,运行在同一浏览器中的框架、标签页、窗口间的通信一直多受到严格的限制。但是现实中还存在一些合理的让不同站点的内容能在浏览器内进行交互的需求,其中Mashup就是一个典型的例子,它是各种不同应用的结合体。为了满足上述需求,引入了一种新的功能:跨文档消息通信。其可以确保iframe、标签页、窗口间安全地进行跨源通信。
发送消息使用postMessage API,其示例代码如下:
chatFrame.contentWindow.postMessage(content,url);
接受消息时,需要在页面中添加一个事件处理函数,当消息到达时,通过检查消息的来源来决定如何对这条消息如何处理,示例代码如下:
window.addEventListener("message",messageHandler,true);
function messageHandler(e){
switch(e.origin){//表示数据发送源
case "friend.example.com":
//处理消息
processMessage(e.data);//发送方实际传送的消息
break;
default:
//其他消息来源
//消息被忽略。
}
}postMessage API提供了一种交互方式,使得不同源的iframe之间可以进行消息通信。
HTML5 通过引入源的感念对域安全进行了阐明和改进。源是网络上用来建立信任关系的地址的子集。源由规则(scheme)、主机(host)、端口(port)组成,例如由于scheme(https、http)不同,则源不同。
跨源通信通过 源来确定发送者,这就使得接收方可以忽略或者拒绝来自不可信源的消息。同时需要通过添加监听事件来接受消息,以避免被不可信应用程序的信息所干扰。但是在使用外来消息时,即便是可靠的数据源,也同样要谨慎,以防止内容注入。
在使用postMessage API时,需要遵循以下步骤:
1、检查浏览器是否支持
if(typeof window.postMessage === undefined){
//浏览器不支持postMessage
}2、发送消息
window.postMessage("Hello","xx.example.com");第一个参数包含要发送的数据,第二个参数时消息传递的目的地。
如果要发送消息给iframe,则使用如下代码:
document.getElementById("iframe")[0].contentWindow.postMessage("Hello","xx.example.com");3、监听消息事件
window.addEventListener("message",messageHandler,true);
var originWhiteList = ["a.example.com","b.example.com","c.example.com"];
function messageHandler(e){
if(checkWhiteList(e.origin)){
processMessage(e.data);//发送方实际传送的消息
}else{
//忽略发送的消息
}
}
function checkWhiteList(origin){
for(var i = 0; i<originWhiteList.length; i++){
if(origin === originWhiteList[i]){
return true;
}
}
return false;
}二、XMLHttpRequestLevel2
XMLHttpRequestLevel2是XMLHttpRequest的改进版本,主要涉及:跨源XMLHttpRequess和进度事件(Progress events)。
XMLHttpRequest仅限于同源通信,XMLHttpRequestLevel2通过跨资源共享实现(Cross Origin Resource Sharing)跨源XMLHttpRequests。
在XMLHttpRequest中通过readystatechange事件来响应进度,但是其在某些浏览器中不被兼容。XMLHttpRequestLevel2用了一个有意义的名字Progress进度来命名进度事件。其进度事件的名称主要有loadstart、progress、abort、error、load、loadend。通过对程序属性设置回调函数,可以实现对这些事件的监听。
在使用XMLHttpRequestLevel2时,需要遵循以下步骤:
1、检查浏览器是否支持
var xhr = new XMLHttpRequest();
if(typeof xhr.withXredentials === undefined){
//浏览器不支持XMLHttpRequest
}2、构建跨源请求
var crossOriginRequest = new XMLHttpRequest();
crossOriginRequest.open("GET","http://www.example.com",true);在请求过程中,务必确保能够监听到错误,以找出出错原因,解决问题。
3、使用进度事件
crossOriginRequest.onprogress = function(e){
var total = e.total;
var loaded = e.loaded;
if(e.lengthComputable){
//处理其他事情
}
}
crossOriginRequest.upload..onprogress = function(e){
var total = e.total;
var loaded = e.loaded;
if(e.lengthComputable){
//处理其他事情
}
}三、postMessage API示例应用
以跨源聊天应用为例,来演示门户页面和聊天部件之间的交互。
1、创建postMessagePortal.html页面
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>跨源通信-WebChat</title>
<link rel="stylesheet" href="styles.css">
</head>
<h1>跨源通信门户</h1>
<p><b>源</b>: http://portal.example.com:8080</p>
状态 <input type="text" id="statusText" value="Online">
<button id="sendButton">更改状态</button>
<p>
使用postMessage发送一个状态,以更新包含在此页面中的widgetiframe。
</p>
<iframe id="widget" src="http://chat.example.net:8080/communication/postMessageWidget.html"></iframe>
<script>
var targetOrigin = "http://chat.example.net:8080";
var notificationTimer = null;
function messageHandler(e){
if(e.origin == targetOrigin){
notify(e.data);
}else{
//忽略
}
}
function sendString(s){
document.getElementById("widget").contentWindow.postMessage(s,targetOrigin);
}
function notify(message){
alert(message);
}
function sendStatus(){
var statusText = document.getElementById("statusText").value;
sendString(statusText);
}
function loadDemo(){
document.getElementById("sendButton").addEventListener("click",sendStatus,true);
sendStatus();
}
window.addEventListener("load",loadDemo,true);
window.addEventListener("message",messageHandler,true);
</script>2、创建postMessageWidget.html
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>widget</title>
<link rel="stylesheet" href="styles.css">
</head>
<h1>Widget iframe</h1>
<p><b>源</b>: http://chat.example.net:8080</p>
<p>通过门户设置状态为: <strong id="status"></strong> <p>
<p>
<input type="text" id="messageText" value="Widget notification.">
<button id="actionButton">发送通知</button>
</p>
<script>
var targetOrigin = "http://portal.example.com:8080";
window.addEventListener("load",loadDemo,true);
window.addEventListener("message",messageHandler,true);
function loadDemo(){
document.getElementById("actionButton").addEventListener("click",
function() {

