Cache-Control是HTTP协议的一部分,是在请求和响应中必须服从的指令,通常用于提高页面加载,阻止页面缓存对请求和响应造成不利的干扰。
Cache-Control 为单向指令,即请求中存在的指令,并不意味着响应中存在同样的指令
一、请求
1. Cache-Control
RFC:7234#5.2.1 Request Cache-Control Directives
允许的指令 | 值 | 含义 |
---|---|---|
max-age | delta-seconds | 客户端不愿意接受age超过这个值的缓存。并且不接受过期缓存,除非max-stale存在。 |
max-stale | delta-seconds | 如果有值,客户端可以接受过期时间不超过指定值的缓存 如果没有值,客户端愿意接受过期缓存而无论过期过久。 |
min-fresh | delta-seconds | 客户端愿意接受一个新鲜度不小于当前age加上指定时间的响应。简单说在指定的后续一段时间内不会过期的响应。 |
no-cache | 无 | 客户端示意缓存,在使用缓存的时候必须进行校验。 |
no-store | 无 | 客户端示意缓存,不要存储本次请求的响应。但是对于已经缓存的内容则没有影响。 |
no-transform | 无 | 不得对资源进行转换或转变。Content-Encoding, Content-Range, Content-Type等HTTP头不能由代理修改。例如,非透明代理可以对图像格式进行转换,以便节省缓存空间或者减少缓慢链路上的流量。 no-transform指令不允许这样做。 |
only-if-cached | 无 | 客户端只接受缓存给出的响应,如果缓存没有命中应该返回一个504 |
2. ETag
Etag 是URL的Entity Tag,用于标示URL对象是否改变,区分不同语言和Session等等。具体内部含义是使服务器控制的,就像Cookie那样。
通常把ETags和GET请求的“If-None-Match”头一起使用,这样可利用客户端(例如浏览器)的缓存。因为服务器首先产生ETag,服务器可在稍后使用它来判断页面是否已经被修改。本质上,客户端通过将该记号传回服务器要求服务器验证其(客户端)缓存。
请求流程
Etag由服务器端生成,客户端通过If-Match或者说If-None-Match这个条件判断请求来验证资源是否修改。常见的是使用If-None-Match.请求一个文件的流程可能如下:
====第一次请求===
1.客户端发起 HTTP GET 请求一个文件;
2.服务器处理请求,返回文件内容和一堆Header,当然包括Etag(例如”2e681a-6-5d044840”)(假设服务器支持Etag生成和已经开启了Etag).状态码200
====第二次请求===
1.客户端发起 HTTP GET 请求一个文件,注意这个时候客户端同时发送一个If-None-Match头,这个头的内容就是第一次请求时服务器返回的Etag:2e681a-6-5d044840
2.服务器判断发送过来的Etag和计算出来的Etag匹配,因此If-None-Match为False,不返回200,返回304,客户端继续使用本地缓存;
作用
Etag 主要为了解决 Last-Modified 无法解决的一些问题。
1. 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
2. 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒)
3. 某些服务器不能精确的得到文件的最后修改时间;
为此,HTTP/1.1引入了 Etag(Entity Tags).Etag仅仅是一个和文件相关的标记,可以是一个版本标记,比如说v1.0.0或者说”2e681a-6-5d044840”这么一串看起来很神秘的编码。但是HTTP/1.1标准并没有规定Etag的内容是什么或者说要怎么实现,唯一规定的是Etag需要放在”“内。
4. 有些URL是多语言的网页,相同的URL会返回不同的内容。还有不同的Session有不同的Cookie也就有不同的内容。这种情况下如果过 Proxy,Proxy就无法区分导致串门,只能简单的取消cache功能。Etag解决了这个问题,因为它能区分相同URL不同的对象。
二、响应
1. Cache-Control
允许的指令 | 值 | 含义 |
---|---|---|
must-revalidate | 无 | 一旦缓存过期,必须向源服务器进行校验,不得使用过期内容。如果无法连接必须返回504。 |
proxy-revalidate | 与must-revalidate相同,但仅对公共缓存生效。 | |
no-cache | field-name | 如果值,在没有成功通过源站校验的情况下不得使用缓存。 有值,在进行验证的时候不要发送值指示的头域。 如Cache-Control: no-cache="set-cookie,set-cookie2" ,表示不要携带cookie进行验证。 |
no-store | 无 | 不要缓存当前请求的响应 |
no-transform | 无 | 与请求头语义相同 |
public | 无 | 任何缓存都可以进行缓存,即使响应默认是不可缓存或仅私有缓存可存的情况。 |
private | field-name | 没有值,公有缓存不可存储;即使默认是不可缓存的,私有缓存也可以存储 。有值,将无值时的作用,限制到指定头字段上。公有有缓存不可存储指定的头字段,而其他字段可以缓存。 |
max-age | delta-seconds | 在经过指定时间后将过期 |
s-maxage | delta-seconds | 指定响应在公共缓存中的最大存活时间,它覆盖max-age和expires字段。 |