下面的内容展示了一个常见的 Response Headers,这些 Headers 要求客户端最多缓存 3600 秒,也给出了一个 pub1259380237;gz
的校验值。
HTTP/1.x 200 OK
Transfer-Encoding: chunked
Date: Sat, 28 Nov 2009 04:36:25 GMT
Server: LiteSpeed
Connection: close
X-Powered-By: W3 Total Cache/0.8
Pragma: public
Expires: Sat, 28 Nov 2009 05:36:25 GMT
Etag: "pub1259380237;gz"
Cache-Control: max-age=3600, public
Content-Type: text/html; charset=UTF-8
Last-Modified: Sat, 28 Nov 2009 03:50:37 GMT
X-Pingback: http://net.tutsplus.com/xmlrpc.php
Content-Encoding: gzip
Vary: Accept-Encoding, Cookie, User-Agent
对于缓存而言,我们主要用了 Etag,Cache-Control 和 Last-Modified。
Cache-Control
Cache-Control 是指缓存指令,这个指令控制谁在什么条件下可以缓存响应,以及可以缓存多久。这个协定取代了以前的 Expires
指令,在 HTTP/1.1 开始支持,在这么长时间后,我们可以认为 Cache-Control 在正常环境下都是支持的。Cache-Control的格式如下:
Cache-control: must-revalidate Cache-control: no-cache Cache-control: no-store Cache-control: no-transform Cache-control: public Cache-control: private Cache-control: proxy-revalidate Cache-Control: max-age=<seconds> Cache-control: s-maxage=<seconds>
谁可以缓存
public 与 private 用来指定谁可以缓存。public 是指任何资源都可以被缓存下来,即使某些部分需要 http 验证的情况下; private 则是要求针对单一用户进行缓存,其他用户是无法使用这一块缓存的。
怎么缓存
no-cache,no-store 与 no-transform 来指定怎么缓存。“no-cache”表示必须先与服务器确认返回的响应是否发生了变化,然后才能使用该响应来满足后续对同一网址的请求。因此,如果存在合适的校验值 (ETag),no-cache 会发起往返通信来验证缓存的响应,但如果资源未发生变化,则可避免下载。相比之下,“no-store”则要简单得多。它直接禁止浏览器以及所有中间缓存存储任何版本的返回响应,例如,包含个人隐私数据或银行业务数据的响应。每次用户请求该资产时,都会向服务器发送请求,并下载完整的响应。如果没有指定这个字段,那么就认为是可以缓存的。
缓存多久
指令指定从请求的时间开始,允许获取的响应被重用的最长时间(单位:秒)。例如,max-age=60 表示可在接下来的 60 秒缓存和重用响应。
Last-Modified and If-Modified-Since
除了服务端发送的 Cache-Control 指令外,可以做的更灵活一些,毕竟不是所有请求都适用于不变的 max-age。If-Modified-Since 和 Last-Modified 这一对就是另一种灵活的解决方案。
Last-Modified 是由服务端返回的,用于告知客户端最后一次修改是什么时候。客户端需要记录下来这个值,并在下一次请求的时候,通过 If-Modified-Since 这个字段附上上一次服务端返回的 Last-Modified 的值。在这种情况下,服务端就有了两次时间,在通过比对后,就可以知道在这段时间内,内容是否发生了改变。如果没有发生变化,就会返回 304 NOT MODIFIED
这个状态码,而不是通常的 200。反之如果发生了变化,就进行正常的返回。
Etag and If-None-Match
还记得前面提交的 Etag 吗?这是从另一种维度上来确定 Cache 是否需要更新。服务端会返回相应的 Etag,这个 Etag 客户端不用关心其具体是怎么实现的,只需要能够记录下这个值就行。服务端是通过对内容进行 hash,或者别的算法来生成这样的 Etag,当客户端请求的时候,只需要去检查两者是否相同,即可知道内容有没有发生变化。返回的方式,与前面 If-Modified-Since and Last-Modified 相同。