HTTP协议中与浏览器缓存有关的部分

本文来自: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

响应头信息示例:

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
这时浏览器便会缓存 Last-Modified 值,但再次访问的时候(强制刷新除外)就会发送 If-Modified-Since请求头
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   (原文可能会更新,请感兴趣的朋友直接访问)

全文完。

你可能感兴趣的:(java,Web,cache,浏览器)