HTTP 头部 cache 控制字段

2010年1月21日 由 月影鹏鹏 留言 »

关于 cache 控制

HTTP/1.0 提供了一种简单的 cache 机制。一个源头服务器,使用一个带有时间戳的 Expires 头部标识在一个响应中,这样的意思就是表示何时过期。进一步还有条件请求:在请求头部中包含一个 If-Modified-Since 字段,指定的是响应头中的 Last-Modified 时间戳,这样服务器就响应 304,暗示被缓存的条目是有效的,或者重新取一遍条目之后返回 200。
HTTP/1.0 还包含一个机制:Pragma: no-cache,对于客户端而言,意思是一个请求不能从 cache 中获得。
HTTP/1.0 的机制大体上是没有问题的,但是可能有缺点,没有允许服务器或者客户端对 cache 进行完全的或者明确的控制。

HTTP/1.1 尝试提供明确的和可扩展的协议机制,保留了 1.0 中的设计。
在 1.1 中,一个 cache 条目在达到过期时间之前是新鲜的,在过期之后则是不新鲜的。一个 cache 不需要丢弃一个不新鲜的条目,但是在返回给客户端之前,它通常必须重新从源头服务器那里获得,协议允许源头服务器和终端用户来覆盖这种行为。

在 HTTP/1.0 中,一个 cache 条目使用 If-Modified-Since 条目来重新强刷获得一个条目,它使用了绝对时间戳,带来的明显问题就是时间偏移可以。因此在 HTTP/1.1 中引入了更一般的概念:etag。HTTP 服务器将 etag 头部放在响应中。但问题是在大网站中多台机器的同一资源 etag 应该相同,但实际计算出来不同,因此不适合使用。

HTTP/1.1 包括一些额外的新的条件请求头,除了 If-Modified-Since 之外。最基本的是 If-None-Match,它允许一个客户端对一个请求的资源进行多种表示(tag),这些表示发给服务器之后如果没有一个表示可以匹配资源当前的 tag 值,服务器将返回一个正常的响应,否则它将返回一个 304 头部并带有 etag 指示哪个表示是合理的。

HTTP/1.1 也加入了一些新的条件请求头部:If-Unmodified-Since 和 If-Match,它们创建了其他类型的请求条件,特别是在 Range 请求中。

HTTP/1.1 头部添加了 Cache-Control 头部,既可以出现在请求中,又可以出现在响应中。由于在 1.0 当中绝对时间戳的缺陷,1.1 中使用 max-age 带上的是相对时间表示 cache 的最大有效时长。它也引入了单独的 Age 头部,因此 cache 可以暗示一个响应已经在 cache 中存在了多久。
由于用户有隐私需求,private 和 no-store 指令允许服务器和客户端阻止部分或者全部内容的存储,实际上,这并不保证隐私,真正的加密机制才能保证隐私。

cache-control 的值分为几类:
什么是可以被 cache 的:
public
指示响应可被任何缓存区缓存。
private
指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。
no-cache
指示请求或响应消息不能缓存 ,则 cache 不能使用响应来满足随后请求,它必须成功与源头服务器校验之后才可以。

cache 可以保存什么
no-store
用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。
这个指令适用于整个消息,可以应用在请求头或者响应头中。如果在请求中发送,则一个 cache 不能存储这个请求或者随后的响应。如果发送在响应中,一个 cache 不可以存储响应的任何部分以及相关的部分。

基本过期机制的修改
一个条目的过期时间可以由源头服务器使用 Expires 头部或者 max-age 来指定。cache-control max-age 暗示了响应是可以被 cache 的(比如 public)除非某些更严格的指令也在场。

如果一个响应同时包括 Expires 头部和 max-age,则 Expires 将被覆盖。
max-age
指示客户端愿意接受存活时间不大于这里指定的描述的响应。除非 max-stale 也存在,否则客户端将不愿意接受不新鲜的响应。
min-fresh
客户端要一个新鲜时间至少是这么多的响应。
max-stale
指示客户端愿意接受一个超过了过期时间的响应。如果 max-stale 后面带有值,则它不能接受过期时间超过这个值的响应,如果没有值,则可以接受任何时候的过期响应。

cache 的校验和重新加载
must-revalidate
协议包括一个机制来让源头服务器要求所有后续响应都必须重新刷新一个 cache 条目。当一个 must-revalidate 指令出现在响应中时,cache 在首先从源头服务器那里重新刷新之前,不可以使用这个不新鲜的条目。

在 Firefox 中,请求 Nginx 下的静态文件,如果先前已经请求过:

If-Modified-Since: Wed, 24 Jun 2009 11:09:27 GMT
Cache-Control: max-age=0

HTTP/1.x 304 Not Modified
Server: nginx/0.7.64
Date: Tue, 08 Dec 2009 06:06:23 GMT
Last-Modified: Wed, 24 Jun 2009 11:09:27 GMT
Connection: keep-alive

如果 F5 刷新,或者再开,就是上面的结果,如果 Ctrl + F5 刷新,则:

Pragma: no-cache
Cache-Control: no-cache

HTTP/1.x 200 OK
Server: nginx/0.7.64
Date: Tue, 08 Dec 2009 06:08:50 GMT
Content-Type: image/gif
Content-Length: 1853
Last-Modified: Wed, 24 Jun 2009 11:09:27 GMT
Connection: keep-alive
Accept-Ranges: bytes

在 Nginx 中,有几个地方是和响应头部 cache 相关的几个字段的涉及:
ngx_http_not_modified_filter_module.c:根据 if_modified_since 来决定响应代码;
ngx_http_core_module 中的 if_modified_since:让你决定如何处置 If-Modified-Since 字段;
upstream, proxy, fastcgi 模块:对 cache-control 的控制;
ngx_http_headers_filter_module.c:让你自己加额外的头部;
ngx_http_header_filter_module.c: 在这里确定输出头部字符串。

至于 cache-control 中的其它字段,貌似没有涉及到。

参考:

http://hi.baidu.com/78000672/blog/item/2f37c7deac206a1963279890.html

http://aayy520.blog.163.com/blog/static/231822602009114638738/

http://www.bizeway.net/read.php?519

广告位

留言