4. no-cache指令:重新验证机制与ETag配合使用

📌 概念解释:no-cache ≠ 不缓存

no-cache 是 Cache-Control 指令中最容易被误解的一个。它的字面意思是“不要缓存”,但实际语义是:每次使用前都必须向服务器验证缓存副本是否仍然有效。换句话说,no-cache 允许浏览器将响应存储在本地缓存中,但禁止直接使用缓存副本——必须先通过条件请求与服务器确认资源是否修改。

💡 记忆口诀:“no-cache 不是不存,而是不用;用之前,先问服务器同不同意。”

与之对比,no-store 才是真正的禁止缓存——响应不能被存储在任何缓存层中。二者区别显著:

指令 是否存储缓存 是否直接使用缓存 典型场景
no-cache ✅ 允许存储 ❌ 必须先验证 动态内容、实时数据、敏感但可重用的信息
no-store ❌ 禁止存储 — 银行交易、个人隐私、一次性令牌

🔁 重新验证机制:如何工作

当客户端(浏览器或代理)持有标记了 no-cache 的缓存副本时,会发生以下步骤:

  1. 用户请求资源 → 客户端检查本地缓存,发现存在 no-cache 条目。
  2. 客户端不会直接使用该缓存副本,而是构造一个条件请求发给服务器。
  3. 服务器根据条件判断资源是否变化:
    • 若资源未改变 → 返回 304 Not Modified(无响应体),客户端使用本地缓存。
    • 若资源已改变 → 返回 200 OK + 最新资源,客户端更新缓存并呈现。
⚠️ 关键细节:no-cache 不能保证客户端一定会重新验证——如果客户端实现有缺陷或配置错误,可能跳过验证。现代浏览器和合规的 HTTP 缓存系统均遵守此行为。

🔗 ETag配合使用:高效验证的钥匙

ETag(实体标签)是服务器为资源分配的版本标识符,通常为哈希值或版本号。当与 no-cache 配合时,ETag 承担条件请求中的验证依据:

  • 客户端在条件请求中发送 If-None-Match: "etag-value" 头。
  • 服务器比对发送的 ETag 与当前资源的 ETag:
    • 匹配 → 304,客户端使用缓存。
    • 不匹配 → 200 + 新资源 + 新 ETag。

ETag 具有强验证和弱验证两种类型:

类型 前缀 语义 示例
强 ETag 无 资源任何字节变化都会产生不同 ETag "abc123"
弱 ETag W/ 语义相等即可,允许细微变化(如空白字符) W/"abc123"
🔎 为什么 no-cache 必须配合 ETag 或 Last-Modified? 如果没有验证机制,no-cache 会导致客户端每次请求都要获取完整资源(200 + 全量响应体),失去缓存意义。ETag 或 Last-Modified 让服务器能返回轻量级 304 响应,显著降低带宽消耗。
no-cache + ETag 重新验证流程 客户端发起请求 本地有 no-cache 缓存 构造条件请求 If-None-Match 服务器比对 ETag ETag 匹配? 匹配 → 304 / 不匹配 → 200 304:使用本地缓存 200:更新缓存 🔑 使用强验证 ETag 保证资源精确匹配 🔄 验证后立即生效 缓存副本状态更新

📋 常见误区

误 区 真 实 含 义
“no-cache 就是不缓存” 允许缓存,但每次使用前必须向服务器验证。
“no-cache 可以不用 ETag” 可以只用 Last-Modified,但 ETag 提供更精确的验证能力。
“ETag 是 no-cache 专属” ETag 可与任何缓存策略配合使用(如 max-age、must-revalidate)。
“304 响应不包含任何头信息” 304 必须包含 ETag、Last-Modified 等验证头,否则缓存可能失效。

🧪 练习题

  1. 选择题:某资源响应头为 Cache-Control: no-cache,以下哪种说法正确?
    • A. 客户端每次都必须重新下载整个资源
    • B. 客户端可以缓存该资源,但使用前需发送条件请求
    • C. 客户端不能存储该资源的任何副本
    • D. 该资源一定没有 ETag

    答案:B

  2. 判断题:ETag 配合 no-cache 时,服务器收到 If-None-Match 后若资源未改变,应返回 200 OK。

    答案:错误。应返回 304 Not Modified。

  3. 场景分析:一个新闻 API 使用 Cache-Control: no-cache,但没有 ETag,所有请求都返回 200 + 完整 JSON。你会如何优化?

    答案:添加 ETag(如基于文章列表内容的哈希),让客户端携带 If-None-Match 请求,使未变更时返回 304,减少带宽和延迟。

🔍 应用边界

no-cache 最适合以下场景:

  • 高频变化但不可预测的资源:如股票价格、实时排行榜、公告系统——资源可能频繁更新,但无法预知何时变化。
  • 需要精确一致性的数据:如库存数量、订单状态——即使毫秒级过时也绝不能使用旧缓存。
  • 用户敏感内容:如个人信息面板、账户余额——必须确保显示最新数据。

不适合场景:

  • 不可缓存或不应缓存的机密数据(应使用 no-store)。
  • 几乎不变化的静态资源(应使用 max-age + 版本号,避免不必要的验证开销)。