上篇文章我简要的介绍了下网站静态化的演进过程,有朋友可能认为这些知识有点过于稀松平常了,而且网站静态化的技术基点也不是那么高深和难以理解,因此它和时下日新月异的web前端技术相比,就显得不伦不类了。其实当我打算写本系列的之前我个人觉得web前端有一个点是很多人都知道重要,但是有常常低估它作用的,那就是web前端和web服务端如何融合的这个点上,这个点再加上我们要做出一个规模庞大,高并发,快速响应的网站时候它对于web前端的架构技术的演进起到了一个不可忽视的作用。
网站的web前端要实现高效,第一个要解决的短板就是网络的延迟性对网站的加载效率的影响,当然很多人会说网速快不快这是网络运营商的问题,不是网站的问题,但是大家肯定也见过就算我们用上了千兆宽带也会有些网站加载速度慢的让人无法忍受,网站本身的确是没法控制网络速度的能力,但是如果我们不降低网络对页面加载效率的影响,其他任何优化网站的手段也就无从谈起,原因就是网络效率对于网页加载效率的影响是起到大头作用的,只有这个大头被解决了,那么解决其他的小头才能发挥作用。
回到上文讲到的网站静态化的关键点动静分离,解决这个关键点的本质就是为了降低网速对网站加载效率的影响,但是我们在处理动静分离问题时候采取的策略不同会对我们整个网站架构产生重大影响,特别是将网页做好动静拆分后,静态的资源尽力向浏览器端推移,这就导致了前端架构出现了以前服务端才有的MVC模式,这就导致web前端架构产生了质的变化,如是一些原来适用于flash这样的重客户端的技术也被传统的web前端所采用,MVC模式在web前端进一步演进由此而出现了MVP(Model-View-Presenter)模式,MVVM(Model-View-ViewModel)模式。也许上篇文章里有人对讲述动静分离的原理有点异议,但是当今日新月异的web前端技术就是这些常见技术不断演化而来,这就是我上篇想表达的内容,我觉得这个系列的特点应该是细节,这是和上个系列存储的瓶颈注重思想是有所不同的。
动态网站最难以动静分离的就是页面了,其他的静态资源例如:图片、外部脚本文件等等这些和静态网站的手法基本一致,其实业界很早就关注了动态网站的动静分离问题,并且为不同的动静分离方案都进行了总结,今天我就介绍下这些技术。本人web服务端的工作语言是java,因此下面服务端的例子是使用java的web技术阐述的,其他语言例如php都有与之对应的技术,所以请那些不是使用java作为服务端工作语言的朋友可以类比学习。
在java的web开发里,页面技术jsp本身就包含了将页面动静分离的手段,例如下面的代码:
<%@ include file=”header.jsp” %>
<body>
……….
<%@ include file=”footer.jsp” %>
一般一个网站的头部和尾部都是一样,因此我们把头部的代码单独放置在一个header.jsp页面里,页面尾部的代码放置下footer.jsp页面里,这样技术人员在开发页面时候就不再需要重复编写这些重复的代码,只需要引用即可,这个做法最大的好处就是可以避免不同页面在相同代码这块的不一致性,假如没有这个统一引用的话,手动编写或者复制和粘贴,出错的概率是非常的高的。
但是这个做法有一个问题,问题就是这种动静分离其实都是作用于单个页面的,也就是说每个页面都要手动的重复这个动静分离的操作,大多数情况这种做法都不会有什么问题,但是对于一个大型网站而言这种做法就有可能会制造不必要的麻烦,这里我截取了一张京东的首页,如下图所示:
讲述前我要事先声明下,京东网站可能不存在我要讲述的问题,我这里只是使用京东网站的首页做例子来说明,看图里的首页和食品两个条目,有些公司做这样的网站时候这些导航进入的页面会是一个独立的工程,每个工程都是由独立的项目组开发维护的,虽然项目组不同但是他们页面的整体结构会是一致的,如果按照上面的动静分离手段,那么每个项目组都要独立维护一份相同的头部尾部资源,这个时候麻烦来了,如果该公司要新增个新的条目,那么每个项目组都要更新自己不变的资源,如果该企业一共分了5个项目组,现在又做了一个新的条目,那么其他与之无关的项目组都得折腾一次更改统一引用文件的工作,要是做的不仔细就有可能出现页面展示不一致的问题,为了解决这个问题,java的web开发里就会考虑使用模板语言替代jsp页面技术,例如模板语言velocity,这些模板语言都包含一个布局的功能,例如velocity就有这样的功能,我们看看velocity的布局模板实例,如下所示:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>#springMessage("page_upop_title")</title> <meta http-equiv="X-UA-Compatible" content="requiresActiveX=true"/> <meta name="keywords" content='#springMessage("page_upop_keywords")'/> <meta content='#springMessage("page_upop_description")' name="description"/> </head> <body oncontextmenu="return false" onselectstart="return false"> #if($pageHead) #parse($pageHead) #end $screen_content #parse($page_footer) </body> </html>