您的位置:首页 > Web前端 > HTML5

HTML5新特性之Communication

2015-05-31 22:06 246 查看
Communication是众多HTML5新特性中比较重要的一个,它提供一种基于安全策略的跨站交互的机制,即使来自不同的站点的应用之间也能自由的通信,正是这一特性的出现,使得不同站点内容的集成简化了许多。

我们都知道,基于安全方面的考虑,浏览器会合理地限制脚本的执行,禁止访问其他站点的数据服务或操作非本站点的DOM对象,这些安全机制在一定程度上消除了安全攻击的隐患,但也给前端开发者带了一定的麻烦,我们不得不采取一些“曲线救国”的手段来实现跨站通信的功能。但随着HTML5的逐渐成熟,我们使用Communication API去解决这些问题,一切都是那么简单。今天我们主要来介绍一下Communication API中跨文档消息通信以及应用案例。

我们这里所要讲解的是一个跨站资源整合的例子,假如我们的站点需要为用户呈现一些多元化的资源信息,这些资源可能不是由我们自己提供,而是和其他的站点合作,由他们分别来提供,就像下面图示那样,在主站点有一个搜索框,然后下面嵌入合作站点的两个信息展示页面,一个是新闻站点,另外一个是股票站点,分别显示不同的信息,如果用户在主站点输入关键字并点击搜索,内嵌的合作站点就会受到消息,然后分别去服务端请求数据,最终将搜索结果呈现到主站点。





我们可以看到搜索前后的变化,当用户用关键字搜索时,会同时触发两个站点的搜索操作,然后每个站点搜索完成后都会将自己搜索结果数量汇总到主站点,所以主站显示8个搜索结果,是两个内嵌站点结果数量之和。

现在让我们来看看主站点页面的结构:

<div>
<input id="keyword" type="text"/>
<button onclick="search()">Search</button>
<span id="results">
<b id="resultsNum"></b> results.
</span>
</div>

<!--news module-->
<iframe id='newsModule' src="http://test.news.com:8082/index.html"></iframe>

<!--stocks module-->
<iframe id="stocksModule" src="http://test.stocks.com:8083/index.html"></iframe>
从上面代码可以看出,我们用了两个iframe分别引入了两个不同站点的页面,而http://test.integration.com:8081正是我们的主站点,它将两个不同站点的资源整合在了一起。
我们知道,如果URL中的协议、域名和端口中有任何一个不同,就认为是跨域的,所以很明显,我们嵌入的两个页面都是跨域资源,主页面是无法通过脚本去操作内嵌页面DOM的,自然无法执行内部的代码,如图所示:



那么我们如何能够通知内嵌页面去执行相应的操作呢,这就涉及到了一个非常重要的API,那就是postMessage函数:

function search() {

var keyword = document.getElementById('keyword').value;
var newsOrigin = 'http://test.news.com:8082';
var stocksOrigin = 'http://test.stocks.com:8083';

document.getElementById('newsModule').contentWindow.postMessage({keyword: keyword}, newsOrigin);
document.getElementById('stocksModule').contentWindow.postMessage({keyword: keyword}, stocksOrigin);
}
可以看到,当执行search函数时,我们先回取到用户输入的关键字,然后分别获取到每个iframe的window对象,然后调用postMessage函数,该函数有两个重要的参数,第一个是要传递的数据,可以传递字符串或者对象;第二个参数指定目标的源,包括协议、域名以及端口。

通过postMessage函数,消息就被发送到内嵌站点页面了,那么我们如何接受消息呢?我们可以注册message事件,比如我们可以在news的页面中这样处理:

var searchFromServer = function(keyword, callback) {
//fake search logic

var resultsNum = 3;
document.getElementById('display').textContent = resultsNum + ' records by: ' + keyword;

callback(resultsNum);
};

window.addEventListener('message', function(e) {
var allowed = {
'http://test.integration.com:8081': true
};
if (allowed[e.origin]) {
var keyword = e.data.keyword;
searchFromServer(keyword, function(resultsNum) {
window.top.postMessage({resultsNum: resultsNum}, 'http://test.integration.com:8081');
});
}
}, false);
可以看到,内嵌的news站点页面中注册了message事件并指定了处理函数,事件参数e包含两个重要属性,origin表示消息发送方的origin,data表示消息中包含的数据,其中origin非常重要,我们可以判断消息来源是否为合作伙伴的站点,这样就可以过滤一些非法请求了。接下来,searchFromServer函数被调用,这个函数模拟了服务器请求,直接指定3条搜索结果,并传递到回调函数中,而在回调函数中,通过window.top获取到最顶层的window对象,然后向其发送一条消息,将搜索结果数量作为数据传送到我们的主站点。

现在就让我们来看看主站点是如何处理这个消息的,我们对主站点的逻辑稍加修改:

var resultsNum;

function search() {
resultsNum = 0;

var keyword = document.getElementById('keyword').value;
var newsOrigin = 'http://test.news.com:8082';
var stocksOrigin = 'http://test.stocks.com:8083';

document.getElementById('newsModule').contentWindow.postMessage({keyword: keyword}, newsOrigin);
document.getElementById('stocksModule').contentWindow.postMessage({keyword: keyword}, stocksOrigin);
}

window.addEventListener('message', function(e) {
var allowed = {
'http://test.news.com:8082': true,
'http://test.stocks.com:8083': true
};
if (allowed[e.origin]) {
resultsNum += e.data.resultsNum;

document.getElementById('results').style.display = 'inLine';
document.getElementById('resultsNum').textContent = resultsNum;
}
}, false);

同样,我们是注册了message事件,并判断消息源是否为news或stocks,我们还添加了一个resultNum变量,每次开始搜索时置0,然后接收到news或stocks返回的结果数量后将结果数量显示出来。搜索的整个过程如图所示:



这个过程看起来似乎很简单,不过要在本地运行起来,还需要一些配置,接下来我们就讲解一下如何配置及运行这个实例。

概况来讲,我们需要以下几个步骤:

1. 修改hosts,配置映射域名

2. 安装基于Node.js平台的http-server简单Web服务包

3. 分别以不同端口启动三个应用

首先,修改我们本机的hosts,添加一下三行配置,保证我们通过指定域名访问时,系统会自动映射到本机:

127.0.0.1 test.news.com
127.0.0.1 test.stocks.com
127.0.0.1 test.integration.com
接下来,我们需要配置Web服务,请确保我们本机已经安装Node.js环境,然后执行下面的命令:

npm install http-server -g
最后,我们就需要分别启动三个站点了,我们的目录结构如下:



所以我们在Communication目录下,分别进入这三个子目录,然后启动各自的服务,只需执行以下命令:

cd integration
http-server -p 8081

cd news
http-sever -p 8082

cd stocks
http-server -p 8083
大功告成,现在我们访问test.integration.com:8081就可以看到我们上面展示的页面了。不过最后需要注意的是,我们需要使用比较新的浏览器才支持这个新特性,当然我们在实际开发中可以用下面这种方式检测浏览器的支持情况:

var isMessageSupported = 'postMessage' in window;
我们今天先到这里,希望大家能够亲自搭建环境并测试一下上面介绍的示例,并能够体会并掌握跨文档消息通信的新特性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: