如何利用HTTP缓存提升网页性能

网站的性能(Performance)要考虑两方面,一方面是在Server端的运行效率,另外一方面是在Client端感觉到的效率。不要觉得 Server端效率高这个网站或者服务给用户的体验就是高效的,若是不考虑影响Client Performance的因素,Server端跑得再快用户也可能感受慢得和牛同样。html

Yahoo的哥们作的研究真不是盖的,他们还写了本书《High Performance Web Sites》详细介绍若是提升Client Performance。公司内部也有一个Team作这方面的事情,听过他们的培训,和Yahoo说的差很少,所谓英雄所见略同。前端

给静态资源(HTML文件,图片文件等)的Repsone加上Expires/Cache-Control Header是颇有效的一招。若是HTTP Response中有Expires这样的Header的话,浏览器会Cache这个资源,理想情况下(注意,只是理想情况),在Expire Date以前,不会再发HTTP请求给Server要这个资源,不过Expires的值只能是一个固定日期,好比“Thu 27 Nov 2008 07:00:00 GMT”,不能是一个相似“从如今开始以后10年”这样一个随机浮动的值,若是要这样的效果,能够用Cache-Control这样的Header,若是 HTTP Resposne中有这样的Header:“Cache-Control: max-age = 100”,表示这个资源在cache中的最大寿命是100秒。通常说来这种静态文件永远不该该过时,若是真的要给这个Cache加上一个期限,那我但愿是 ——一万年,“Cache-Control: max-age = 315360000000”;node

其实就应该给Expires设一个永远不会过时的时间,好比你如今有一个文件叫logo.gif,须要用一个新的logo的时候,你不要去覆盖原来 的文件,而把新的logo存成logo_v2.gif,让相关网页引用新的logo_v2.gif,这样可让新老网页同时工做,实在犯不上为了节省存储 空间覆盖原有文件。算法

对Apache服务器,使用mod_expires,在httpd.conf或者.htaccess中加上浏览器

<FilesMatch "\\.(ico|gif|jpg|html)$">
ExpiresDefault "access plus 10 years"
</FileMatch>

对于IIS 6(IIS 7还不清楚),经过IIS Manager能够经过GUI添加Expires/Cache-Control,经过命令行修改就麻烦一点了。 服务器

首先要到IIS的AdminScripts目录下去找到adsutil.vbs文件。网络

cd C:\Inetpub\AdminScripts ide

好比咱们要给根目录下的imags目录添加Expires/Cache-Control,先要在metabase中给它加一个节点性能

cscript adsutil.vbs create W3SVC/1/root/images "IisWebVirtualDir"网站

若是但愿访问images目录下的文件得到Cache-Control: max-age=60,就这样

csript adsutil.vbs set W3SVC/1/root/images/HttpExpires "D, 0x3c"

若是但愿访问images目录下的文件得到“Expires: Thu 27 Nov 2008 07:00:00 GMT”,就这样

csript adsutil.vbs set W3SVC/1/root/images/HttpExpires "S, Thu 27 Nov 2008 07:00:00 GMT"

还有,同一个HTTP Response中能够同时有Expires和Cache-Control,可是Cache-Control权限比Expires大,会override它的。

HTTP的Response中还会有另一个Header叫Last-Modified,好比“Last- Modified: Thu, 06 Apr 2006 21:17:12 GMT”,浏览器访问一个URI获得这样的Resposne以后,就知道这个资源最后一次的修改时间,下次须要再次得到这个资源的时候,会发一个 Request给Server,不过这个Request中有一条“If-Unmodified-Since: Thu, 06 Apr 2006 21:17:12 GMT”,若是在Server端在这个日期以后对这个资源进行了修改,就会照常返回这个资源给Client端,可是若是没有修改,就会返回一个304 (Not Modified) Response而不返回资源,告诉Client端:“这个资源从上次给你之来历来没改过,你放心用你Cache中的好了。” 一个304 Response比一个静态资源一般小多了,这样就节省了网络带宽。

让咱们回过头来比较一下Expires和Last-Modified这两个东西,彷佛Last-Modified比不上Expires,由于虽然它 可以节省一点带宽,可是仍是逃不掉发一个HTTP请求出去,而Expires却使得浏览器干脆连HTTP请求都不用发,岂不痛快!那还要Last- Modified这个物体干什么?理想情况的确是这样,不过当用户在IE或者Firefox里面按F5或者点击Refresh按钮的时候(不是在URL栏 里从新输入一遍URL而后回车),就算对于有Expires的URI,同样也会发一个HTTP请求出去,因此,Last-Modified仍是要用的,而 且要和Expires一块儿用。

除了Last-Modified,HTTP Response中还可能有另一个Header: ETag, 使得Server上的静态资源有点“版本控制”的味道;假如HTTP Response中包含“ETag: "abcdefg1234:0001"”,等于告诉Client端,你拿到的这个版本的资源有个ID,叫作abcdefg1234:0001,下次须要发 Request索要同一个URI的时候,在Request里面加一条“If-None-Match: "abcdefg1234:0001"”,好,Server端作了一些修改,下次这个Client再来了一个请求,可是这时候资源已经改了,因此返回这个 新资源,还有新的tag “ETag: "abcdefg4567:0001"”(这个etag我是胡写的),这样,Client端等于Cache了两份,在须要索要这个资源的时候,能够包含这 样的Header: “If-None-Match: "abcdefg1234:0001" "abcdefg4567:0001"”,这样,即便Server端头脑发热,把这个资源Roll back回原来的版本,依然会返回304 (Not Modified) Response,由于它知道Client端Cache着之前的版本呢,这点功能是Last-Modifed/If-Not-Modified无法作到 的。

不过ETag/If-None-Match这点功能实在是个鸡肋,首先,Server端的资源不大可能Roll Back,更重要的是,有可能形成Client Performance降低。对于只有一个Server的网站,没什么问题,可是如今稍微上点规模的网站都须要Scale Out,也就是说须要前端一个Load Balancer,后面接多台Server来处理请求,俗称Cluster,既然是Cluster,那么每一个请求到底返回什么结果应该和分配到哪一个 Server无关,不过这个ETag可能就坏事了。假如用户的第一次请求分配给Server A,返回“ETag: "abcdefg1234:0001"”,可是第二次请求分配给了Server B,Server B上这个资源和Server A上的如出一辙,可是计算出这个资源的ETag是"abcdefg1234:0002",这下麻烦了,虽然内容同样,可是ETag不匹配,仍是浪费了带宽 把资源发送了一遍,冤枉啊!而事实上,不一样Server上的ETag颇有可能不一样,对于Apache,ETag的计算考虑了inode,对于 IIS,ETag考虑了metabase的修改版本,要保证不一样server上的这些信息一致,有点小难。不过不是有Last-Modified/If- Not-Modified吗?Server端看到If-Modified-Since,对照一下时间对得上,无论If-None-Match,能够直接发 回304(Not Modified)呀,很不幸,RFC2616对这种状况作了规定,若是既有If-None-Match又有If-Modified-Since,除非二者不冲突,否则不会返回304。

因此说ETag就是一个害人精,按照Yahoo的建议,别费劲想办法同步不一样Server上的ETag了,干脆就把ETag删除得了(缺 省,Apache和IIS都是有ETag的),我Sniff了一下Yahoo的若干网页返回HTTP Response,的确没有ETag,人家的确是知行合一;

对于Apache,在httpd.conf或者.htaccess中加一行就搞定了:

FileETag none

对于IIS 6,可就有点费劲了,首先,彷佛没有办法经过Config来把ETag去掉,查了不少资料,问了不少人,彷佛可以去掉ETag的办法只有写一个ISAPI Filter来弄,Sniff了一下Microsoft的几个网页的结果显示ETag都妥当当的存在,估计目前真的没有什么好方法。

只好退而取其次,保证不一样Server上的ETag一致了。 IIS对Etag的计算算法是ETag = {Filetimestamp:ChangeNumber}, Filetimestamp保持一致没什么问题,ChangeNumber是metabase的change number,就有点难保证Cluster中每一个Server都同样了,因此,干脆就把它设成固定值好了,这个链接告诉咱们该怎么办,很惋惜,没有找到完全删除ETags的配置。

---------------------------------------------------------------------
相关文章
相关标签/搜索