缓存
Expires
HTTP/1.0 用 Expires 指定缓存过期的时间字符串。
http
Expires: Wed, 21 Oct 2015 07:28:00 GMT缺点:
- 基于客户端系统时间判断缓存的有效性,不够可靠
- 缓存过期后只能重新传输一份数据,对于数据没有改变的情况是多余的
Cache-Control
HTTP/1.1 新增 Cache-Control 指定缓存策略。
| Request | Response |
|---|---|
| max-age | max-age |
| max-stale | |
| min-fresh | |
| s-maxage | |
| no-cache | no-cache |
| no-store | no-store |
| no-transform | no-transform |
| only-if-cached | |
| must-revalidate | |
| proxy-revalidate | |
| must-understand | |
| private | |
| public | |
| immutable | |
| stale-while-revalidate | |
| stale-if-error | stale-if-error |
Response
max-age=xxx:缓存有效期,以秒为单位- 从资源产生时开始计算,浏览器存储时会减去
Age - 优先级高于
Expires
- 从资源产生时开始计算,浏览器存储时会减去
s-maxage=xxx:类似max-age,只用于共享缓存- 共享缓存 (shared):在代理服务器、CDN 上存储
- 优先级高于
max-age
no-cache:允许缓存,但是每次请求都必须重新验证,无论缓存是否过期must-revalidate:当缓存过期时必须重新验证- 当无法连接服务器时,HTTP 默认允许使用过期的缓存,加上该指令可以禁止这种行为
proxy-revalidate:类似must-revalidate,只用于共享缓存no-store:禁止缓存- 禁止缓存新响应,但不禁止旧缓存的使用
private:只能在浏览器缓存public:允许作为共享缓存must-understand:只有当理解基于状态码的缓存要求时才缓存资源no-transform:禁止修改资源immutable:缓存有效期内资源不会发生修改stale-while-revalidate=xxx:缓存过期后的一段时间内,允许使用过期的缓存,同时在后台重新验证- 减少响应时间,提升用户体验
stale-if-error:缓存过期后重新验证时,如果遇到错误 (500/502/503/504),在指定时间段内允许使用过期的缓存
Request
no-cache:强制重新验证,尽管缓存还没过期- 当用户强制刷新页面时,浏览器会带上这个指令
no-store:避免缓存请求和响应- ⚠️ 大部分浏览器不支持
max-age=xxx:允许使用缓存的有效期要求- 很多浏览器用
max-age=0代替no-cache来刷新页面
- 很多浏览器用
max-stale=xxx:允许使用过期一段时间的缓存- ⚠️ 大部分浏览器不支持
min-fresh=xxx:禁止使用剩余有效期过短的缓存- ⚠️ 大部分浏览器不支持
no-transform:与响应报文的指令含义相同only-if-cached:只返回缓存,即使已经过期,如果没有缓存返回 504
Vary
- 缓存默认通过 URL 区分,相同的 URL 会返回相同的缓存,但有一些例外
- 通过
Accept、Accept-Language、Accept-Encoding进行内容协商,不同的请求头会返回不同的内容,应该分开缓存 - 可以在
Vary中指定缓存的 key,比如:
Vary: Accept-Language缓存查找时就会同时考虑 URL 和 Accept-Language 的值:

Last-Modified
资源的最后修改时间。
http
Last-Modified: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT过期缓存重新验证时,发送包含 If-Modified-Since 的报文,值为缓存的生成时间。
http
If-Modified-Since: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMTLast-Modified 也用于爬虫、CMS 等应用。
缺点:
- 部分文件会周期性修改,但是内容不一定变化,会造成缓存不必要的失效
- 部分文件修改非常频繁,以秒为粒度的
Last-Modified无法准确描述 - 一些文件系统无法精确得到文件的修改时间,可能影响缓存的准确性
ETag
- 服务端生成、区分资源是否修改的字符串,比如哈希值、版本号等
- 优先级高于
Last-Modified
http
ETag: W/"<etag_value>"
ETag: "<etag_value>"- 缓存过期重新验证时,把
ETag的值放入If-None-Match,请求服务端资源是否被修改 - 优先级高于
If-Modified-Since
http
If-None-Match: "<etag_value>"
If-None-Match: "<etag_value>", "<etag_value>", …
If-None-Match: *强缓存
本地缓存命中且未过期,直接使用本地缓存的资源。
协商缓存
- 缓存过期,带上
If-Modified-Since或If-None-Match请求服务端 - 资源未修改,返回
304 Not Modified,重新设置缓存有效时间,使用本地缓存 - 资源已修改,返回
200 OK和资源的最新版本- 服务端
Last-Modified晚于If-Modified-Since - 服务端
ETag与If-None-Match不同
- 服务端
优点
- 减少响应时间
- 降低服务器负载
- 节省带宽