于吉吉的技术博客

建造高性能门户网

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  65 随笔 :: 6 文章 :: 149 评论 :: 0 Trackbacks
记得问过身边的一些开发工程师(非前端)缓存要分几个层次,从哪里做起,答案很多,比如反向代理缓存,DNS缓存,memcached,数据库缓存等等,确实很完整,不过好像漏掉了我们用户跟我们联通的最根本的工具浏览器,确实好似很少有人把用户的浏览器当作是web站点的组成部分来看待

缓存协商
现在我们需要将用户的浏览器也纳入我们构建网站各个缓存层次中的其中一个重要层次,网站信息和内容在由web服务器生成,而将这些信息和内容作为一段二进制的文件作为本地缓存文件存放在用户的浏览器,是两个独立个体共同完成的任务,所以两者之间需要一种沟通的机制,也就是HTTP的缓存协商

Last-Modified和If-Modified-Since协商
Last-Modified和If-Modified-Since分别位于响应头信息和请求头信息中,都是记录请求的页面最后的修改时间
在第一次访问web服务器会返回200状态,并在浏览器的响应头Last-Modified上写上此页面最后修改的时间戳
使用firebug进行查看




在再次访问时,浏览器会把第一次返回Last-Modified的时间戳记录到If-Modified-Since,并作为请求头信息发送到服务区,web服务器会通过If-Modified-Since上的时间戳来判断用户的页面是否是最新的,如果不是最新的,则返回新的页面并修改响应头Last-Modified时间戳给用户,如果判断是最新的,则返回304状态并告诉浏览器本地的cache页面是最新的,浏览器可以直接加载本地页面,这样可以减少网络上传输的数据,并且也减少服务器的负担。




这里需要注意的是,HTTP协议中规定使用的是GMT时间(格林威治),而我们国家使用的是GMT+8的时间,所以我们从firebug中看到的时间是比我们早了8个小时,不过这没关系,它并不影响到缓存的对比工作

Etag协商
如果我们的一个文件存放在多台web服务器上,用户的请求在这些服务器上之间轮询,实现负载均衡,那些这个文件在各台web服务器的最后修改时间很可能是不一样,这样用户每次请求到的web服务器都可能是不同,Last-Modified和If-Modified-Since则无法对应,导致每次都需要重新获取内容,这时候采用直接标记内容的Etag算法,就可以避免上述的问题
Etag是由Web服务器生成的,如Apache为一个静态文件新增响应头为
Etag    "e3af4060-5-472bedf076880"
浏览器获得这个Etag后,便会在下次请求该页面时,在HTTP的请求头附上If-None-Match    "e3af4060-5-472bedf076880",与web服务器上的Etag值相比较,如果是相同的话,便返回304状态,不同则重新返回新页面信息



当然啦,这里要指出浏览器缓存只针对HTML和HTM进行而动态文件则无法缓存,浏览器并不在乎你的文件是否动态还是静态,浏览器只认准和web服务器通讯的HTTP协商,所以只要动态页面HTTP头信息包含的缓存协商信息,动态内容也是可以一样被浏览器进行缓存的,和静态页面无什么两样,只是你确定你需要这样做,让动态页面被缓存?
以下是对一个jsp进行写头信息

response.addHeader("Last-Modified",DateUtl.format(new java.util.Date())+" GMT");
response.addHeader(
"ETag","e3af4060-5-472bedf076880");


同样,这样两个设置会写入浏览器的响应头,这个动态文件跟静态文件一样会被浏览器缓存

Expires
Expires标记告诉浏览器该页面何时过期,并且在此过期前不需要再访问web服务器,直接使用本地的缓存文件即可,这样请求响应头都不需要,确实节省了带宽和服务器的开销,但是就算页面在web服务器上更新后在Expires过期前也不会出现在用户面前,究竟是否应该在于我们的实际应用和取舍
下面是Apache中提供的mod_expires模块
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault A600
ExpiresByType image/x-icon A2592000
ExpiresByType application/x-javascript A604800
ExpiresByType text/css A604800
ExpiresByType image/gif A2592000
ExpiresByType image/png A2592000
ExpiresByType image/jpeg A2592000
ExpiresByType text/plain A86400
ExpiresByType application/x-shockwave-flash A2592000
ExpiresByType video/x-flv A2592000
ExpiresByType application/pdf A2592000
ExpiresByType text/html A600
</IfModule>

或者
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 12 hours"
ExpiresByType text/html "access plus 3 days"
ExpiresByType text/plain "access plus 3 days"
ExpiresByType text/css  "access plus 7 days"
ExpiresByType image/gif "access plus 30 days"
ExpiresByType image/png "access plus 30 days"
ExpiresByType image/jpeg "access plus 30 days"
ExpiresByType image/x-icon "access plus 30 days"
ExpiresByType video/x-flv  "access plus 30 days"
ExpiresByType application/x-shockwave-flash "access plus 30 days"
</IfModule>


我们在jsp文件也可以指定expires的过期时间

response.addHeader("Expires",DateUtl.format(new java.util.Date())+" GMT");



当然啦,你再刷新也不会返回304状态,因为浏览器已经不用想web服务器发出请求

----------------------------------------

by 陈于喆
Mail: chenyz@corp.netease.com


参考文章
郭欣 《构建高新能web站点》
中文版 《HTTP协议(RFC2616)》
posted on 2010-08-25 00:03 陈于喆 阅读(6424) 评论(0)  编辑  收藏 所属分类: web开发缓存

只有注册用户登录后才能发表评论。


网站导航: