Cache-Control 同时写 no-store 与 max-age:含义与验收方法

用敏感响应与公开响应的独立样例,区分 no-store、max-age、no-cache、private 和 public,再核对实际发出的响应头。

Cache-Control: no-store, max-age=3600 并不是未定义行为。对这个组合,遵循规范的缓存不得存储响应或用它满足其他请求;新鲜度时长不会覆盖 no-store。

作者:Evan•发布:2026年3月19日•更新:2026年9月29日•预计阅读 3 分钟

本指南涉及工具

1. 按完整指令组合判断

把 no-store, max-age=3600 粘贴到 Cache-Control 解析器。它同时包含禁止存储和一小时新鲜度,但 RFC 9111 中 no-store 对私有缓存和共享缓存都有效,因此这里的 max-age 没有可供复用的新鲜度用途。这表示策略意图冗余,不代表缓存会随机选择指令。

如果应用与 CDN 表现不同,用 HTTP 响应头解析器查看最终头部,并与源站配置对照。中间件或边缘规则可能追加或覆盖头部。解析器只能解释粘贴值,不能观察或验证线上缓存。RFC 9111 §5.2.2.3 对 must-understand 的独立例外不属于这里的双指令样例。

2. 敏感响应保留禁止存储策略

对于返回账号账单或新签发凭据的测试接口,可使用 Cache-Control: no-store。额外添加 private 对禁止存储是冗余的,因为 no-store 已覆盖私有和共享缓存。不要为了提高命中率或消除提示而直接删除 no-store。

如果业务允许用户浏览器保存响应,但禁止共享缓存保存,private 才有不同的作用。例如 private, no-cache 允许私有缓存存储,但每次复用前都必须验证成功。只有允许响应保存在用户设备上时才采用该策略;它不等于 no-store。

private 和 no-store 都不能代替身份认证、HTTPS 或缓存访问控制,也不会自动清除所有设备上此前缓存的响应。出现错误用户数据时,应调查缓存键、认证边界和边缘覆盖规则,不能仅凭 no-store 与 max-age 并存就认定原因。

3. 非敏感内容明确设置新鲜度

假设一份公开发布说明 JSON 对所有访问者都完全相同,可以采用 Cache-Control: public, max-age=300,并提供类似 "release-v2" 的 ETag。它允许缓存,五分钟的新鲜度仍受 HTTP Age 计算和其他缓存规则约束。过期后,缓存可发送 If-None-Match 来验证该表示。

public 允许共享存储,甚至能放开某些原本禁止缓存的情况;private 则排除共享存储。不能因为 URL 看起来像静态地址,就给个性化响应套用 public。先检查 Cookie、Authorization 的处理、实际响应内容,以及 CDN 缓存键。

如果公开响应允许存储,但每次复用前都必须验证,可以使用带 ETag 的 Cache-Control: no-cache。no-cache 不是“永不存储”,它要求复用前验证成功。内容已经变化时,通常应返回新响应体,而不是 304。

4. 用一次性资源验收线上行为

通过正常线上路径重复请求同一个测试 URL,记录状态码、Cache-Control、存在时的 Age、ETag,以及 CDN 文档规定的缓存状态字段。观察缓存复用时不要开启浏览器开发者工具的 Disable cache;使用普通请求,不要把强制刷新当作常规复用行为。

no-store 样例的预期是 HTTP 缓存不存储、不复用。public 样例则先在新鲜期内重复请求,再在过期后检查是否发生验证。仅凭缺少 Age 或两次都返回 200,不能判定是否用了缓存,应结合 CDN 或源站日志判断。

如果把某个响应从 public 改为 no-store,应按平台要求检查并清除已有共享缓存条目。新头部只有被接收后才生效;验收这种迁移时保持测试载荷不含敏感信息。

查阅 HTTP 缓存规范