3. CacheControl 指令详解:max‑age、no‑cache、no‑store、must‑revalidate 等常用值
3.1 原理:Cache‑Control 在 HTTP 缓存中的角色
HTTP 的 Cache‑Control 头部是服务端与客户端协商缓存策略的核心协议。OkHttp 的缓存模块完全遵循 RFC 7234,通过解析该头部中的指令来决定是否缓存、缓存多久以及何时必须重新验证。每个指令都是一个键值对或标记,组合后形成完整的缓存策略。
在同步请求场景中,Cache‑Control 直接影响 OkHttp 的 CacheInterceptor 行为:
- 请求指令(由客户端发送)—— 告知服务端或中间缓存客户端的偏好,例如只接受新鲜度低于 30 秒的资源。
- 响应指令(由服务端返回)—— 指示缓存层如何存储和复用该响应。
本章聚焦响应指令中四个最常用的值,并延伸介绍 public、private、s‑maxage 等辅助指令。
3.2 核心指令速查表
| 指令 | 方向 | 语义 | 典型值示例 | 对 OkHttp 缓存的影响 |
|---|---|---|---|---|
| max‑age | 响应 / 请求 | 资源在缓存中的最大有效秒数 | max‑age=3600 |
缓存过期前可直接复用;过期后需重新验证或丢弃 |
| no‑cache | 响应 | 缓存必须向源服务器验证资源是否仍有效 | no‑cache |
每次使用前都会发起条件请求(If‑Modified‑Since / ETag) |
| no‑store | 响应 | 禁止任何中间缓存或私有缓存存储该响应 | no‑store |
OkHttp 不会将响应写入磁盘缓存,直接透传 |
| must‑revalidate | 响应 | 缓存过期后必须向源服务器验证,不得使用过期缓存 | must‑revalidate |
即使设置了 max‑age,过期后也必须回源验证 |
| public | 响应 | 任何缓存(包括 CDN)都可以缓存 | public |
与 max‑age 配合,允许共享缓存存储 |
| private | 响应 | 仅私有缓存(如 App 本地缓存)可以缓存 | private |
OkHttp 视为可缓存,但中间代理不得缓存 |
| s‑maxage | 响应 | 针对共享缓存的专用 max‑age | s‑maxage=600 |
优先级高于 max‑age,但 OkHttp 作为私有缓存会忽略 |
教学提示: 在 OkHttp 中,
no‑cache ≠ no‑store。no‑cache 允许缓存存储响应,但每次使用时必须验证;no‑store 则完全禁止存储。两者常被混淆,但语义差异巨大。
3.3 指令决策流程
当 OkHttp 的 CacheInterceptor 收到服务端响应时,会按照下图顺序检查 Cache‑Control 指令,最终决定是否缓存以及如何设置过期策略。