HTTP协议中的客户端缓存

@ 2009-03-03 23:42:24
标签:

    缓存网页或者其他网络资源(图片,脚本,样式表,等)的好处是显而易见的:

    • 增加了访问速度
    • 减少了网络带宽

    减少网络带宽不仅意味着访问速度的提高,在当网络带宽不是完全免费的情况下,也有着显而易见的好处。

    在HTTP/1.1的RFC中,也提到通过适当使用缓存,可以:

    • eliminate the need to send requests:避免了不必要的请求,从而增加访问速度
    • eliminate the need to send full responses:减少了响应的数据量,从而减少带宽

    HTTP 中的三种缓存机制

    HTTP协议中定义了三种类型的缓存机制:

    • Freshness: 允许客户端无需检查原始服务器上的内容就缓存当前响应。
      • 常用的是ExpiresCache-Control
    • Validation: 允许在当前缓存的内容“过期”后检查原始内容是否已经更新。
      • 比如 Last-ModifiedETag
    • Invalidation: 允许在访问同一个资源时使之前的缓存内容失效。
      • 比如对同一个资源的 POST,PUT 或者 DELETE 请求就会使之前的缓存失效。

    Expires: 指定过期时间

    指定内容的过期时间是最简单的实现客户端浏览器缓存的方法。Expires指定一个时间,告诉浏览器相应的内容在指定时间之前都不会发生变化。浏览器因此也就不需要重新请求文档内容,只需从缓存中读取相应内容就可以了。

    一个 Exprires 响应头看起来如下:

    Expires: Thu, 19 Nov 1981 08:52:00 GMT
    

    如果不希望浏览器缓存当前内容,可以把Expires设置为一个过去的时间。

    但是Expires有着一些明显的缺点:

    • 服务器和客户端时间的不一致可能会导致问题
    • 服务器端很可能忘记了所设置的Expires值,并且无法通知客户端更新内容

    Cache-Control: 更多的控制

    HTTP1.1 中引入了 Cache-Control字段来实现对缓存的更多控制。Cache-Control的值是一组逗号分隔的属性值。

    字段 说明
    max-age=[seconds] 相当于Expires字段,用间隔时间而不是绝对时间
    s-maxage=[seconds] 和 max-age类似,影响代理服务器(proxy)之类的客户端
    public 允许任何客户端进行缓存,包括代理服务器之类面向多个用户的
    private 只允许浏览器这样的单一用户使用的客户端缓存
    no-cache 不允许缓存
    no-store 不允许缓存,也不允许存储在磁盘上。出于安全考虑
    must-revalidate 必须向服务器验证缓存内容的freshness
    proxy-revalidate 和 must-revalidate 类似,不过只用于 proxy cache
    • public 也暗示着允许对于需要HTTP Authentication的请求进行缓存,默认是不允许的

    Cache-Control相应看起来可能如下:

    Cache-Control: max-age=3600, must-revalidate
    

    条件请求:Last-Modified 和 If-Modified-Since

    Last-Modified相应头指定一个时间,告诉浏览器当前文档最后修改时间。浏览器下次访问该文档时会包含一个 If-Modified-Since字段,目的是告诉服务器,只有请求文档的最后更新时间大于指定时间时,才需要服务器重新传送文档内容。 If-Modified-Since的值来自浏览器收到的Last-Modified值。

    如果服务器不需要重新传送文档内容,只需返回相应头 304 Not Modified就可以了。

    Last-ModifiedIf-Modified-Since的样子看起来如下:

    # 服务器 => 客户端
    Last-Modified: Mon, 14 Feb 2011 10:04:00 GMT
    
    #客户端 => 服务器
    If-Modified-Since: Mon, 14 Feb 2011 10:04:00 GMT
    

    条件请求:ETag 和 If-None-Match

    ETagIf-None-Match与Last-Modified 和 If-Modified-Since的机制类似, 不同的是字段值用的不是时间而是一个字符串签名。字符串的值可以是任意值,比如文档内容的md5校验值或者其他。

    举例如下:

    # 服务器 => 客户端
    Etag: "52e6e5972cf66ab866851c59c9900278"
    
    #客户端 => 服务器
    If-None-Match: "52e6e5972cf66ab866851c59c9900278"
    

    Vary:指定更多的影响缓存的字段

    TODO

    HTML Meta Tag 中的缓存机制

    <meta http-equiv=”Expires” content=” Fri, 30 Oct 1998 14:19:41″>
    <meta http-equiv=”Cache-Control” content=”no-cache”>
    

    作用类似于HTTP相应头,但不建议这么做。

    禁止客户端缓存

    如果要禁止各种缓存,在PHP中可以设置如下header:

    header("Expires: Sun, 1 Jan 2000 12:00:00 GMT");
    header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT");
    header("Cache-Control: no-store, no-cache, must-revalidate");
    header("Cache-Control: post-check=0, pre-check=0", false);
    header("Pragma: no-cache");  
    

    参考资源

    标签:

      分享到:
      comments powered by Disqus

      30/34ms