Web页面的聚合技术
近接触到了Mason,并且了解到了它基础之上的一个MVC框架实现,随即联想到做网站以来接触到的各种各样的页面聚合的场景,颇有意思。
?
页面聚合本身是一种“分而治之”的思想,把复杂的页面分割成可以被重用和独立维护的部分,这些部分的来源灵活,可以来自同一个web app中,也可以来自不同的域;可以聚合独立的子页面(页面集成),也可以聚合数据(数据集成),甚至可以聚合子呈现(模板集成)。
?
客户端聚合
?
这种聚合的最大好处在于把聚合的工作分散到如今越来越强势的客户端,减轻了服务端的压力;另一方面,也从一定程度上简化了服务端的设计。客户端聚合在互联网初期比较少见,如今随着客户端性能越来越优秀,客户端聚合的优势逐渐显示出来。
?
最简单的聚合形式:frame聚合。请看谷百搜索。这种聚合形式的局限性在于,即便使用了frame标签,也依然是两个网站,那么两个子页面之间的交互就由于浏览器的安全限制变得困难。这是一种纯粹的静态聚合的形式,使用HTML的include标签亦类似。
?
客户端模板的聚合方式。例如Velocity、FreeMarker这些传统的模板技术,都可以做到客户端的聚合。一方面从服务端获取静态模板页,因为这些页面几乎是纯静态的,因此性能非常高;另一方面通过ajax技术从服务端获取变化的数据,优先展示主页面内容,优化页面展示体验,二者在页面上通过JavaScript的帮助形成最终的页面效果。
举例来说,比如服务端返回的模板片段是:
?
<div id="user.name">${user.name}</div>
?
再通过ajax从服务端获取到的页面数据是:
?
{user:{name:"Jim", age:"15"}}
?
聚合后的效果:
?
<div id="user.name">Jim</div>?
例子非常简单,在这种模式下,对于变化数据的获取,可以使用Node.js接口来实现,并使用JSON作为数据传递形式,这个数据服务的子系统变成了一个完全独立于页面展示的数据服务提供者。
?
关于服务端推送技术:在页面聚合的过程中,有些数据实时性强,或者数据量大,无法一次获取完成,需要多次反复从服务端获取数据,而且,这部分数据产生的时间是由服务端确定的。看一看新浪微博、人人网,这些SNS网站中,都大量应用了这种技术。
服务端推送的方式有几种,而传统BS结构的特点是,数据都是去“拉”的,要服务端主动通知客户端需要绕一点点弯。
?
最简单的方式是轮询。客户端不断地ajax查询服务端(例如每隔1分钟查询一下是否有新的数据),甚至不断刷新页面或者子页面。但是这样的办法存在一个问题,就是大量的查询请求很可能是浪费掉的,例如一小时在线用户,每分钟ajax查询一次数据,查询了60次,只有一次是有数据的,那么剩余59次都是白白浪费的。
?
还有一个办法是被称为“Long Pulling”(例如pushlet技术),服务端在接收到客户端的ajax查询请求时,如果没有数据,不要返回,而是hold住这个HTTP连接,直到有数据了再返回。这里的好处显而易见,但是问题也很明显——大量的连接,因此在这种情况下,多路复用技术(可以参考NIO Server的材料,也可以参见这里)就显得格外有用了。
?
第三种办法采用的比较少,就是采用第三方控件,比如Applet、ActiveX等控件,和服务端交互,他们的交互可以超越网页传统的模型,甚至支持非HTTP的协议,由服务端主动推送数据。
?
服务端聚合
?
服务端聚合的本地模板聚合是最传统的聚合形式,是页面重用的基础,由模板引擎解析运算模板为最终的页面,写入输出流。这里以SiteMesh举例:
?
?
配置一个url mapping文件,再在模板上使用SiteMesh标签:
?
<div class='mainBody'> <sitemesh:write property='body'/> </div>
?
SSI:服务器端嵌入(Server Side Include),这也是为什么很多老网站的URL都是以.stm、.shtm或.shtml结尾的。它的嵌入和html标签里面的include不一样,SSI是为WEB服务器提供的一套命令,这些命令只要直接嵌入到HTML文档的注释内容之中即可生效,但是它的解析需要特定的服务器支持。
?
<!--#include file="extend.htm"-->
?
随着页面缓存在互联网应用世界的称王,Oracle定义了ESI作为一种缓存方式聚合页面的规范,它规定了将Web网页的页面的片段进行缓冲/缓存的技术方式。
?
<esi:include src="http://example.com/1.html" alt="Web页面的集合技术" onerror="continue"/>
?
Portlet聚合。Portlet在早几年的企业门户应用中很常见,它本身是一组规范,也规定了一种聚合页面的方式,可以远程聚合,也可以本地聚合,它可以协助应用将数据实体和展现模板在组网上就分离开,业务节点部署可以非常灵活,Portlet是网站解耦的一大利器:
?
不过Portlet由于在聚合中采用了两次请求转发的方式(一次Action请求、一次render请求),导致效率天然不高。
?
文章系本人原创,转载请注明出处和作者
?