HTTP Header of Cache-Control
常见的有以下几种设置
// 不使用缓存
Cache-Control: no-cache
// 不使用缓存,缓存有效期 0
Cache-Control: max-age=0
// 不使用缓存
Cache-Control: no-store, max-age=0
// 使用缓存,缓存有效期 120s
Cache-Control: max-age=120
它在 HTTP header 中设置,用于控制请求和响应的缓存相关内容,同一个请求中请求头和响应头中不一定会一样,就是请求头设置什么响应头就要返回什么。
常用的值有:
no-store
no-cache
max-age=<seconds>
must-revalidate
private
public
...
它的值可以分为以下三类
- 缓存能力 Cacheability
- 有效期 Expiration
- 校验和重载 Revalidation and reloading
缓存可以分别设置这三部分内容,可以互相独立,也可以多个一起设置,他们分别用于控制是否存储缓存、缓存的有效期时长以及使用缓存前是否必须向服务器发起校验。
缓存能力
* no-store
* no-cache
* private
* public
有效期
* max-age=<seconds>
* min-fresh=<seconds>
* max-stale[=<seconds>]
校验和重载
* must-revalidate
* immutable
no-store
响应不会存储在任何缓存中,它不会影响应已缓存过的内容。也就是新请求不会缓存,不会影响上一次缓存的结果。
假设有下面的请求过程
- 假设有个请求 A,它的响应头 cache-control=max-age=100
- 先请求一次 A,会在本地存储缓存
- 更改 A 的响应头 cache-control=no-store
- 再次发起请求 A,依然获取的是缓存的内容
- 可以通过设置 A 的请求头 cache-control=max-age=0 来获取非缓存内容
no-cache
响应可能存储在任何缓存中,只是在使用缓存前必须通过远程服务器校验一次。这个指令不是用来阻止缓存存储你的响应内容的。
可以理解为不使用缓存,每次请求都会校验缓存是否还是新的,是则继续使用缓存内容(不会在下载),否则重新下载内容。
private
响应只能被浏览器缓存存储。
public
响应可能被任何缓存存储
如果你想不让任何缓存存储你的响应内容,可以使用 no-store
max-age
用来设置资源被视为新鲜的最长时间
must-revalidate
指示一旦资源过期了,缓存在没有通过远程服务器校验成功之前不能使用旧的副本
小结
Cache-Control: no-cache
不使用缓存,响应内容会存储在缓存中,但每次请求都会重新向远程服务器发起校验
Cache-Control: max-age=0
不使用缓存,缓存也会存储,有效期为 0 则每次请求都会向远程服务器发起校验,只是在服务器挂掉或者连接失败的时候还会使用缓存内容。
Cache-Control: no-store, max-age=0
不使用缓存,响应内容不会存储,no-store 新的请求不会缓存,max-age=0 保证每次请求都会校验
Cache-Control: max-age=120
使用缓存,缓存会存储,超过有效期后会向远程服务器发起校验。
Other
Cache-Control: no-cache 和 Cache-Control: max-age=0, must-revalidate 设置的作用是一致的
如果要阻止缓存需要设置 Cache-Control: no-store, max-age=0
问题
1 如何清空一个请求的缓存,使用最新的响应内容?(本地已经有存在的缓存)
假如有一个请求设置为 Cache-Control: max-age=3600,如何清空这个缓存?
方法一:在发起请求是设置标头 Cache-Control: no-cache 或者 max-age=0(需要在客户端增加)
TODO 如果不更改客户端能更新缓存吗?
可以通过设置响应头 Clear-Site-Data,它可以清空当前域下的缓存、cookie、本地存储等,但它目前只在草稿阶段,safari 手机端和 pc 端都不支持。
Clear-Site-Data: "cache", "cookies", "storage", "executionContexts"
参考 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data
2 缓存可以存储在哪些地方?
缓存可以分为本地和共享两大类,本地,eg: 本地浏览器,共享,eg: 代理,网关。
3 怎么检测一个缓存还是有效的?
简而言之就是检查缓存是否是新鲜的,也就是看过期时间,没有超过过期时间就是有效的缓存。
计算缓存的新鲜寿命(freshnessLifetime)
- 如果响应有 max-age 标头,它的值就是缓存的寿命
- 如果响应有 Expires 标头,用它的值减去响应的 header 标头的值就是缓存的寿命
- 其它使用默认的 Heuristic 算法计算缓存的寿命
expirationTime = responseTime + freshnessLifetime - currentAge
基于以上可以计算一个缓存的过期时间 = 接收到响应的时间 + 缓存寿命 - 当前请求时间,只要计算的缓存过期时间大于 0 则缓存就是有效的。
也就是每个新的请求过来,用当前请求的时间代入计算,过期时间大于 0 则可以继续使用缓存。