HTTP 缓存
HTTP - 缓存
Section titled “HTTP - 缓存”HTTP 缓存是一项关键技术,用于提升网站性能和减轻服务器负载。通过将频繁访问的资源副本存储在更靠近客户端的位置(例如,浏览器缓存、代理缓存),后续对这些资源的请求可以更快地得到响应,而无需联系源服务器。
HTTP 缓存的目标包括:
- 降低延迟: 从本地缓存提供内容比通过网络获取快得多。
- 减少网络流量: 避免冗余数据传输,为客户端和服务器节省带宽。
- 减轻服务器负载: 到达源服务器的请求更少,降低其工作负担。
HTTP/1.1 提供了多种机制来控制缓存行为,主要通过服务器设置的响应头实现。关键概念包括资源新鲜度(freshness)和验证(validation)。
Cache-Control 头
Section titled “Cache-Control 头”Cache-Control 是 HTTP/1.1 的通用头部字段,是指定请求和响应缓存策略的主要方式。它由逗号分隔的指令列表组成。
常见的 Cache-Control 响应指令:
Section titled “常见的 Cache-Control 响应指令:”| 指令 | 描述 |
|---|---|
| public | 表示响应可以被任何缓存存储(浏览器、代理、CDN)。 |
| private | 表示响应仅供单个用户使用,共享缓存(例如代理)不得缓存。浏览器缓存仍然可以存储它。 |
| no-cache | 强制缓存在释放缓存副本之前,必须向源服务器提交请求进行验证。这不意味着“不缓存”;而是指“使用前必须重新验证”。 |
| no-store | 缓存不应存储有关客户端请求或服务器响应的任何内容。这适用于敏感信息。 |
| max-age=<seconds> | 指定资源被视为新鲜的最长时间(以秒为单位)。相对于请求的时间。 |
| s-maxage=<seconds> | 类似于 max-age,但仅适用于共享缓存(例如 CDN、代理)。私有缓存会忽略此指令。 |
| must-revalidate | 告诉缓存必须遵循服务器提供的任何关于资源新鲜度的信息。HTTP 允许缓存在特殊条件下提供陈旧(stale)资源;此指令可阻止这种情况。 |
| proxy-revalidate | 类似于 must-revalidate,但仅适用于共享缓存。 |
| immutable | 表示响应体随时间不会改变。资源如果未过期,则不应重新验证。对带有指纹的静态资源(fingerprinted static assets)非常有用。 |
| stale-while-revalidate=<seconds> | 允许缓存在后台重新验证资源的同时,立即提供一个陈旧的资源。提高了用户感知性能。 |
| stale-if-error=<seconds> | 如果尝试向源服务器重新验证资源失败(例如,由于网络错误或服务器错误),允许缓存提供一个陈旧的资源。 |
Example: `Cache-Control: public, max-age=3600, s-maxage=7200, must-revalidate`常见的 Cache-Control 请求指令:
Section titled “常见的 Cache-Control 请求指令:”| 指令 | 描述 |
|---|---|
| no-cache | 客户端需要一个新鲜的响应。缓存必须向源服务器重新验证。 |
| no-store | 客户端请求缓存不要存储该请求或响应的任何部分。 |
| max-age=<seconds> | 表示客户端愿意接受一个其 age(自上次成功验证或生成以来经过的时间)不大于指定时间的响应。 |
| min-fresh=<seconds> | 表示客户端需要一个在未来至少指定秒数内仍然新鲜的响应。 |
| only-if-cached | 客户端只需要缓存的响应。缓存不应联系源服务器。 |
过期头:Expires
Section titled “过期头:Expires”Expires 头是一个较旧的 HTTP/1.0 头部,提供一个绝对日期/时间,指示在此之后响应被视为陈旧。
Example: `Expires: Wed, 21 Oct 2025 07:28:00 GMT`如果同时存在 Expires 和 Cache-Control: max-age(或 s-maxage),则 max-age(或 s-maxage)具有优先权。通常推荐使用 Cache-Control,因为它更灵活。
验证头:ETag 和 Last-Modified
Section titled “验证头:ETag 和 Last-Modified”当缓存资源的新鲜度生命周期过期(例如达到 max-age)或使用 Cache-Control: no-cache 时,缓存需要向源服务器重新验证该资源。这通过带有验证器头的条件请求(conditional requests)完成。
Last-Modified:
服务器可以在其响应中包含 Last-Modified 头,指示资源的最后修改日期。
Example: `Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT`重新验证时,客户端(或缓存)可以在 If-Modified-Since 请求头中将此日期发送回服务器。如果资源没有改变,服务器会响应 304 Not Modified(未修改)并返回空响应体,从而节省带宽。否则,它会发送 200 OK(成功)以及新资源。
ETag (Entity Tag):
ETag(实体标签)是 Web 服务器为特定版本的资源分配的一个不透明标识符。ETag 提供了更强大的验证机制,特别是在修改日期不够精确或不足以区分时(例如,亚秒级的更改)。
Example: `ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"`重新验证时,客户端在 If-None-Match 请求头中发送 ETag。如果该 ETag 与服务器当前版本仍匹配,服务器会响应 304 Not Modified。否则,它会发送 200 OK 以及新资源和新的 ETag。
ETag 可以是“强”的(保证字节级的完全一致),也可以是“弱”的(以 W/ 为前缀,表示语义上的等价)。
- 长期缓存不变资源: 对于版本化的 JavaScript/CSS 文件(例如
app.v1.2.3.js)或带有指纹的图片,使用Cache-Control: public, max-age=31536000, immutable。immutable指令告诉浏览器无需重新验证这些资源。 - 短期缓存或重新验证动态内容: 对于会变化的 HTML 页面或 API 响应,使用较短的
max-age值,或者使用no-cache(强制重新验证),或使用stale-while-revalidate以获得更好的用户感知性能。 - 不缓存敏感数据: 对于包含用户隐私数据的响应,使用
Cache-Control: no-store。 - 使用
Vary头: 如果响应内容取决于请求头(例如,Accept-Encoding用于压缩,Accept-Language用于国际化),请使用Vary头来指示缓存存储不同的版本。示例:Vary: Accept-Encoding, Accept-Language。
合理的缓存配置对于构建快速且可伸缩的 Web 应用程序至关重要。它需要仔细考虑资源的特性和用户需求。