Loading... # HTTP 缓存机制深度解析:基于 RFC 9111 的技术分析 ## 摘要 本文基于 Dan Cătălin Burzo 的技术文章 "HTTP caching, a refresher" 和 RFC 9111 (2022) 标准,对 HTTP 缓存机制进行第一性原理分析。HTTP 缓存是 Web 性能优化的核心技术,涉及从浏览器私有缓存到 CDN 共享缓存的多层架构。本文系统分析了缓存系统的组成要素、决策流程、关键指令及其交互关系。 ## 1. 核心问题定义 HTTP 缓存需要解决的核心问题是: - **减少网络传输开销**:避免重复传输相同内容 - **降低服务器负载**:减少源服务器请求数量 - **提升用户体验**:加快内容加载速度 - **保证内容一致性**:确保用户获取最新或可接受的内容版本 ## 2. 系统组成要素分析 ### 2.1 缓存架构层级 HTTP 缓存链包含多个层级,每个层级有不同的职责和策略:  **私有缓存 (Private Cache)**: - 位于客户端浏览器中 - 仅服务于单个用户 - 可以存储用户特定的内容(如认证后的响应) **共享缓存 (Shared Cache)**: - 包括 CDN 缓存和代理缓存 - 服务于多个用户 - 需要特别注意内容隐私和安全性 **源服务器 (Origin Server)**: - 内容的原始提供者 - 通过 HTTP 头定义缓存策略 ### 2.2 新鲜度判断机制 缓存的核心决策逻辑围绕"新鲜度" (freshness) 展开: **响应年龄 (Age)**: - 自响应生成或最后验证以来经过的时间 - 浏览器会累加中间缓存返回的 `Age` 头 **新鲜度时间线 (Freshness Lifetime)**: - 超过此时间后响应被视为过期 (stale) - 优先级判断顺序: 1. `Cache-Control: max-age=<秒数>` 2. `Expires` 和 `Date` 头之间的时间差 3. 基于 `Last-Modified` 的启发式计算 4. 对于共享缓存,`s-maxage` 优先级最高 ## 3. 缓存决策流程 当缓存收到请求时,遵循以下决策逻辑:  ### 3.1 验证机制 当响应过期后,缓存并非必须丢弃,而是可以通过条件请求进行验证: **验证标识符**: - `Last-Modified: <日期>` → `If-Modified-Since: <日期>` - `ETag: "<值>"` → `If-None-Match: "<值>"` **验证响应**: - `200 OK`:服务器返回新内容 - `304 Not Modified`:缓存内容可继续使用 ### 3.2 过期响应处理 某些情况下,缓存可以返回过期响应: - 与源服务器连接失败 - 服务器返回 5xx 错误 - 配置了 `stale-while-revalidate` 或 `stale-if-error` 指令 ## 4. Cache-Control 响应指令分析 ### 4.1 基础指令 | 指令 | 作用 | 适用场景 | |------|------|----------| | `max-age=<N>` | 定义新鲜度时间线(秒) | 静态资源缓存控制 | | `must-revalidate` | 过期后必须验证成功才能使用 | 需要强一致性的内容 | | `no-cache` | 每次使用前都必须验证 | 动态内容或敏感数据 | | `no-store` | 完全禁止缓存存储 | 敏感个人信息 | | `private` | 仅允许私有缓存 | 用户特定内容 | | `public` | 允许共享缓存 | 公共静态资源 | | `s-maxage=<N>` | 共享缓存的新鲜度时间线 | CDN 策略控制 | | `proxy-revalidate` | 共享缓存的 must-revalidate | 代理缓存控制 | | `no-transform` | 禁止中间人转换内容 | 需要原始格式的资源 | | `must-understand` | 不理解状态码时不缓存 | 面向未来的兼容性 | ### 4.2 扩展指令 (RFC 5861) | 指令 | 作用 | 浏览器支持 | |------|------|------------| | `stale-while-revalidate=<N>` | 允许在过期 N 秒内使用过期响应,同时后台验证 | 良好 | | `stale-if-error=<N>` | 验证失败时允许使用过期 N 秒内的响应 | 较差 | ## 5. Cache-Control 请求指令分析 请求指令代表客户端对响应新鲜度的偏好: | 指令 | 作用 | |------|------| | `max-age=<N>` | 接受年龄不超过 N 秒的响应 | | `max-stale=<N>` | 接受过期不超过 N 秒的响应 | | `min-fresh=<N>` | 偏好至少还有 N 秒新鲜度的响应 | | `no-cache` | 请求缓存先验证再使用 | | `no-store` | 请求缓存不存储此次请求和响应 | | `only-if-cached` | 仅使用缓存,否则返回 504 | ## 6. 浏览器刷新机制 ### 6.1 软刷新 (Soft Reload) - **触发方式**:Ctrl+R (Windows/Linux) 或 Command+R (macOS) - **行为**: - Firefox/Chrome:重新验证主资源,子资源按缓存策略加载 - Safari:无条件请求主资源,子资源按缓存策略加载 ### 6.2 硬刷新 (Hard Reload) - **触发方式**:Ctrl+Shift+R 或 Command+Shift+R (Safari: Command+Option+R) - **行为**:所有资源都发送 `Cache-Control: no-cache` 请求 ### 6.3 immutable 指令的演进史 `immutable` 指令的诞生是一个有趣的协议设计案例: **问题背景**(约 2015 年): - Facebook 发现用户刷新页面时,长期存活的脚本和样式表会产生大量 304 响应 - 当时的软刷新行为会重新验证所有资源 **解决方案演化**: 1. **Firefox 方案**:实现 `immutable` 指令(RFC 8246) 2. **Chrome 方案**:改变软刷新行为(仅验证主资源) 3. **Safari 方案**:跟随 Chrome 的新行为 **当前状态**: - Firefox 和 Safari 支持 `immutable` - Chrome 认为新的刷新行为已足够,无需额外指令 - 指令处于尴尬境地,实际应用有限 ## 7. 认证请求的缓存处理 这是一个容易出错的复杂领域: ### 7.1 默认规则 共享缓存**禁止**存储包含 `Authorization` 头的请求的响应。 ### 7.2 例外情况 以下三个指令可以允许共享缓存存储认证响应: 1. **`public`**:明确允许共享缓存 2. **`s-maxage=<N>`**:为共享缓存定义策略 3. **`must-revalidate`**:带有强验证要求 ### 7.3 防护机制 `private` 指令可以防止其他指令意外使认证响应可被共享缓存。 ## 8. 关键技术洞察 ### 8.1 协议演进的连续性 - RFC 2616 (1999) → RFC 7234 (2014) → RFC 9111 (2022) - 协议更新解决实际部署问题(如 `immutable` 的提出) - 浏览器实现与协议标准相互影响 ### 8.2 实现差异的挑战 不同指南和博客文章的建议不仅是对规范的解读,还包含了对不合规或过时缓存/中间件的防御措施。这说明了实际部署的复杂性。 ### 8.3 缓存不等于存储 `no-store` 的语义说明: - "MUST NOT store" 指不得有意存储到非易失性存储 - 需要尽力从易失性存储中删除 - **不是可靠的隐私保护机制** - 恶意或被攻破的缓存可能不遵守此指令 ## 9. 实践建议 ### 9.1 静态资源 ``` Cache-Control: public, max-age=31536000, immutable ``` ### 9.2 HTML 文档 ``` Cache-Control: no-cache ``` 或配合 ETag 验证: ``` Cache-Control: max-age=0, must-revalidate ETag: "<hash>" ``` ### 9.3 API 响应 ``` Cache-Control: private, no-cache ``` ### 9.4 CDN 优化 ``` Cache-Control: public, max-age=600, s-maxage=3600, stale-while-revalidate=300 ``` ### 9.5 敏感数据 ``` Cache-Control: private, no-store, must-understand, no-store ``` ## 10. 参考资料 1. **RFC 9111** (2022) - HTTP Caching 2. **RFC 8246** (2017) - HTTP Immutable Responses 3. **RFC 5861** (2010) - HTTP Cache-Control Extensions for Stale Content 4. Dan Cătălin Burzo - [HTTP caching, a refresher](https://danburzo.ro/http-caching-refresher/) 5. Mark Nottingham - Caching Tutorial for Web Authors and Webmasters (1998—) 6. Jake Archibald - Caching best practices & max-age gotchas (2016) 7. Harry Roberts - Cache control for civilians (2019–2025) 8. MDN - Web Caching --- *文档生成时间:2026-01-14* *基于原始文章发布时间:2025-12-22* 最后修改:2026 年 01 月 14 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏