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举例:

Web页面的聚合技术

配置一个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="http://bak.example.com/2.html" onerror="continue"/> 

Portlet聚合Portlet在早几年的企业门户应用中很常见,它本身是一组规范,也规定了一种聚合页面的方式,可以远程聚合,也可以本地聚合,它可以协助应用将数据实体和展现模板在组网上就分离开,业务节点部署可以非常灵活,Portlet是网站解耦的一大利器。

Portal使用portlet作为可插拔用户接口组件,提供信息系统的表示层。作为利用servlets进行web应用编程的下一步,portlets实现了web应用的模块化和用户中心化。portlet规范,即jsr(Java Standardization Request )168,是为了实现portal和portlet的互操作。它定义了portlet和portlet容器之间的合约,让portlet实现个性化、表示和安全的api集。规范还定义了怎样在portlets应用中打包portlets。

jsr168的目标是:

定义portlet的运行时环境,即portlet容器

定义portlet和portlet容器之间的api集

提供portlet存储易失数据和持久数据的机制

提供portlet包含servlet和jsp的机制

定义方便部署的portlet打包方法

提供jsr168规范下的portal的二进制portlet便携性

通过WSRP(web service for remote portlet)协议运行符合jsr168规范的远程portlet

将复杂的页面代码交给程序开发人员进行处理,以降低网页设计的难度

假设我是一个intranet网站的管理员,我的公司买了一个能显示新闻信息的第三方portlet应用,该应用允许用户指定跟踪新 闻更新的URL地址,我想借助它为用户显示公司的内部新闻。另一个需求是我不想让用户通过该应用来跟踪任何其它的新闻信息来源。作为管理员,我可以为所有 的用户指定一个用于内部新闻更新的URL地址,同时通过改变portlet应用的部署描述符来取消其它人修改该地址的权限。

Portlet就能实现这一需求,Portlet是由Portlet容器聚合的,用户看到的是一个单一和完整的页面,他并不了解页面中的一个个portlet栏目到底来自何方。

Portlet页面组装过程:

Web页面的聚合技术

Portlet由于在聚合中采用了两次请求转发的方式(一次Action请求、一次render请求),导致效率天然不高。

Web页面的聚合技术

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接《四火的唠叨》

分享到:

发表评论

电子邮件地址不会被公开。

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>


Preview on Feedage: