本文来自:http://www.vktone.com/articles/http_browser_cache.html (原文可能会更新,请感兴趣的朋友直接访问)
1. 缓存协商
1.1)Last-Modified响应头 和 If-Modified-Since请求头
首次访问一个页面时,Web服务器可能会生成Last-Modified响应头,表示文件的最后修改时间。
请求头信息示例:
GET /articles/cpc18.html HTTP/1.1 Host: www.vktone.com User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:16.0) Gecko/20100101 Firefox/16.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.vktone.com/ Cookie: Hm_lvt_0349e3f0156bf70cd93447e10ddda4bb=1352731512700,1352967797808; Hm_lpvt_0349e3f0156bf70cd93447e10ddda4bb=1352967808911 Pragma: no-cache Cache-Control: no-cache这时浏览器便会缓存 Last-Modified 值,但再次访问的时候(强制刷新除外)就会发送 If-Modified-Since请求头响应头信息示例:
HTTP/1.1 200 OK Date: Thu, 15 Nov 2012 08:52:42 GMT Content-Length: 19737 Content-Type: text/html Content-Location: http://www.vktone.com/articles/cpc18.html Last-Modified: Thu, 15 Nov 2012 08:12:19 GMT Accept-Ranges: bytes Etag: "3e1eecee8c3cd1:3b78f" Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET
GET /articles/cpc18.html HTTP/1.1 Host: www.vktone.com User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:16.0) Gecko/20100101 Firefox/16.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Connection: keep-alive Cookie: Hm_lvt_0349e3f0156bf70cd93447e10ddda4bb=1352731512700,1352967797808; Hm_lpvt_0349e3f0156bf70cd93447e10ddda4bb=1352969794340 If-Modified-Since: Thu, 15 Nov 2012 08:12:19 GMT If-None-Match: "3e1eecee8c3cd1:3b78f"
如果请求的文件没有改变,则Web服务器返回304状态,浏览器将从缓存中得到文件内容
HTTP/1.1 304 Not Modified Date: Thu, 15 Nov 2012 08:56:53 GMT Content-Location: http://www.vktone.com/articles/cpc18.html Last-Modified: Thu, 15 Nov 2012 08:12:19 GMT Accept-Ranges: bytes Etag: "3e1eecee8c3cd1:3b78f" Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET
1.2)Etag响应头 和 If-None-Match请求头
Etag表明了文件的一种状态,当文件内容不变时,Etag也不变,反过来也是如此;如果文件内容变化时,Etag也应该发生变化。
Etag没有标准的生成方法,有的Web服务器采用“文件最后修改时间戳+文件长度”来作为Etag,有的可能以 md5摘要来作为Etag。
如果响应头中有 Etag,那么浏览器也会缓存起来。
再次访问该文件时,发出的请求会包含 If-None-Match请求头。
在前面的示例中其实已经有了Etag和If-None-Match的例子。
1.3)关于动态网页,比如 jsp/php/asp 等,不会自动生成 Last-Modified响应头,也不会自动生成 Etag响应头。
这个是程序员根据需要来实现的,如果动态内容不会经常变化,那就可以生成响应的 Last-Modified响应头 或者 Etag响应头。
2. 缓存截止期
2.1)Expires响应头
HTTP中,Expires响应头告诉浏览器该内容在何时过期,暗示浏览器在该内容过期之前不需要再询问服务器,而直接使用本地缓存即可。
Expires: Thu, 15 Nov 2012 09:12:19 GMT
要注意的是:Web服务器默认不会生成Expires响应头,即使是静态页面。不过,一般的Web服务器都可以进行配置,各种Web服务器的配置方式不尽相同。
另外,对于常见的静态文件格式,即使Web服务器返回的响应头中不包含Expires,浏览器也会默认一个过期时间。
比如,IE在某种缓存模式下,对于GIF文件设置为永不过期。
2.2)Cache-Control响应头
有一个问题,通过Expires指定的过期时间,是来自于Web服务器的系统时间,如果用户本地时间与服务器时间不一致,那么浏览器缓存的有效期检查就会受到影响。
幸运的是,在HTTP/1.1中有一个Cache-Control的响应头来弥补Expires的不足,形式如下:
Cache-Control: max-age=<second>
对于静态内容,Web服务器在开启Expires的同时,也会自动添加Cache-Control响应头。
那这样的话,Expires和Cache-Control都有的话,以哪个为准呢?
目前主流的浏览器都优先考虑 Cache-Control ,对于没有 Cache-Control 的,以 Expires 为准。
2.3)动态内容
需要程序员根据实际需要自行添加这几个响应头。
3. 在Java实现的Web Server中,动态内容添加处理缓存有关请求头和响应头
3.1)处理浏览器缓存的代码
下面的示意代码就展示了处理缓存的方式
File f = new File(file);
long lastModified = f.lastModified(); // 发现后面3位的毫秒数不为0
long ifModifiedSince = request.getDateHeader("If-Modified-Since"); // 后面3位的毫秒数为0
//response.setHeader("f1", Long.toString(lastModified));
//response.setHeader("f2", Long.toString(ifModifiedSince));
if (ifModifiedSince != -1) {
// SC_NOT_MODIFIED 304
if (lastModified / 1000L <= ifModifiedSince / 1000L) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
response.setDateHeader("expires", System.currentTimeMillis()+1000*3600);
response.setHeader("Cache-Control","max-age="+3600);
//System.out.println("\n\n\n\n\n cache "+System.currentTimeMillis()+"**************************** \n\n\n\n\n");
return ;
}
}
//System.out.println("\n\n\n\n\n whole "+System.currentTimeMillis()+"**************************** \n\n\n\n\n");
// 要把修改时间设置上
response.setContentLength((int) f.length());
response.setDateHeader("Last-Modified", lastModified);
response.setDateHeader("expires", System.currentTimeMillis()+1000*3600);
response.setHeader("Cache-Control","max-age="+3600);
//out.print("");
3.2)如何测试?浏览器的三种刷新方式
使用 Firefox/FireBug, Chrome, HttpWatch 等工具跟踪 HTTP的请求和响应。
(1) 浏览器地址栏的“转到”或通过超链接跳转:如果已有缓存,会发送 If-Modified-Since 和 If-None-Match,并且 Expires 也有效;
(2) F5 一般刷新:会发送 If-Modified-Since 和 If-None-Match,但是 Expires 无效;
(3) Ctrl+F5 强制刷新:网页中所有内容(图片、js、css等)全部重新加载,不会发送 If-Modified-Since 和 If-None-Match。
本文来自:http://www.vktone.com/articles/http_browser_cache.html (原文可能会更新,请感兴趣的朋友直接访问)
全文完。