HTTP(HyperText Transfer Protocol)是互联网中最常用的协议之一,用于客户端和服务器之间的数据交互。随着 Web 应用的复杂化和数据量的增长,性能优化成为关键问题。
缓存机制最早在 HTTP/1.0 中以 Expires
和 Last-Modified
头部出现,但功能有限。
版本 | 时间 | 主要改进 |
---|---|---|
HTTP/1.0 | 1996 (RFC 1945) | 引入 Expires , Last-Modified |
HTTP/1.1 | 1997 (RFC 2068), 1999 (RFC 2616) | 引入 Cache-Control , ETag , Vary 等更细粒度控制 |
HTTP/2 | 2015 (RFC 7540) | 支持多路复用,提升传输效率,不影响缓存语义 |
HTTP/3 | 2022 (RFC 9114) | 基于 QUIC 协议,进一步减少延迟,缓存机制保持一致 |
类型 | 位置 | 是否共享 | 生命周期 |
---|---|---|---|
浏览器缓存(私有缓存) | 用户本地浏览器 | 否 | 仅当前用户使用 |
代理缓存(共享缓存) | CDN 或反向代理服务器 | 是 | 多个用户共享 |
服务器端缓存 | 源服务器或缓存服务器 | 可配置 | 可跨请求复用 |
[请求资源]
↓
是否有缓存?
↙ ↘
否 → 请求源服务器 → 存储响应 → 返回内容
是 → 验证是否新鲜? → 新鲜 → 返回缓存内容
↘ 不新鲜 → 请求验证(If-None-Match / If-Modified-Since)
↙ ↘
304 Not Modified 200 OK + 新内容
Expires
指定资源过期时间(绝对时间),格式为 GMT 时间。
Expires: Wed, 01 Jan 2025 00:00:00 GMT
缺点:
Cache-Control
现代缓存控制的核心头部,提供丰富的指令控制缓存行为。
指令 | 含义 |
---|---|
public |
允许任何缓存存储响应(包括共享缓存) |
private |
仅允许客户端缓存(不能被中间代理缓存) |
no-cache |
使用前必须重新验证(不强制重新下载) |
no-store |
禁止缓存(每次都请求源服务器) |
max-age=xxx |
缓存最大有效时间(单位秒) |
must-revalidate |
过期后必须验证新版本 |
proxy-revalidate |
适用于共享缓存,要求重新验证 |
s-maxage=xxx |
仅用于共享缓存的最大生存时间 |
示例:
Cache-Control: public, max-age=3600, s-maxage=86400
表示浏览器可缓存 1 小时,CDN 可缓存 1 天。
ETag
/ If-None-Match
ETag
是服务器为资源生成的唯一标识符(如哈希值)。
ETag: "abc123"
当客户端再次请求时,带上:
If-None-Match: "abc123"
服务器比较 ETag:
304 Not Modified
200 OK
和新内容优点:
Last-Modified
/ If-Modified-Since
Last-Modified
表示资源最后修改时间:
Last-Modified: Tue, 01 Jan 2024 00:00:00 GMT
客户端下次请求带上:
If-Modified-Since: Tue, 01 Jan 2024 00:00:00 GMT
服务器比较时间戳决定是否返回新内容。
缺点:
Vary
告诉缓存服务器根据请求头的不同来区分缓存。例如:
Vary: Accept-Encoding
表示不同编码方式(gzip、br)应分别缓存。
常用于:
由 Cache-Control
或 Expires
控制,在有效期内直接使用本地缓存。
缓存已过期时,通过 ETag
或 Last-Modified
与服务器协商是否需要更新。
缓存类型 | 验证方式 | 响应码 |
---|---|---|
强缓存 | Cache-Control / Expires | 200(本地缓存) |
协商缓存 | ETag / Last-Modified | 304(未修改)或 200(新内容) |
用户 → CDN 边缘节点 → CDN 区域节点 → 源服务器
CDN 缓存优势:
Cache-Control
,避免频繁回源Vary
处理压缩、设备适配等场景s-maxage
指定 CDN 缓存时间Cache-Control: public, max-age=31536000, immutable
immutable
:表示资源永远不会改变,浏览器可以永久缓存(适用于带 hash 的文件名)Cache-Control: private, no-cache
Cache-Control: public, max-age=60, stale-while-revalidate=30
stale-while-revalidate
:缓存过期后仍可使用旧内容,后台异步刷新Cache-Control: private, no-store
资源类型 | 推荐缓存时间 |
---|---|
静态资源(CSS/JS/图片) | 1年(配合 hash 文件名) |
页面 HTML | 0(no-cache) |
API 数据 | 根据业务需求(如 1分钟 ~ 1小时) |
用户敏感数据 | no-store |
对静态资源添加 hash 值作为版本号:
<script src="/app.js?v=abc123">script>
或使用构建工具生成带 hash 的文件名:
<script src="/app.abc123.js">script>
然后设置:
Cache-Control: public, max-age=31536000, immutable
Vary
处理压缩Vary: Accept-Encoding
确保 gzip 和 br 压缩版本分别缓存。
stale-while-revalidate
提升用户体验Cache-Control: public, max-age=60, stale-while-revalidate=30
Age
和 X-Cache
调试缓存命中CDN 通常会返回:
Age: 120
X-Cache: HIT
帮助开发者判断是否命中缓存。
工具 | 功能 |
---|---|
Chrome DevTools Network 面板 | 查看请求状态码、缓存命中情况 |
curl -I | 获取响应头信息 |
Postman | 模拟请求并查看缓存头 |
CDN 日志分析 | 查看缓存命中率、回源率 |
Lighthouse | 审计网站性能,包括缓存配置建议 |
答:
Cache-Control
或 Expires
判断是否直接使用缓存。ETag
/ Last-Modified
与服务器验证是否需要更新。区别:
Cache-Control
有哪些常用指令?如何组合使用?答:
public
: 所有缓存都可以存储private
: 仅客户端缓存no-cache
: 使用前必须验证no-store
: 禁止缓存max-age
: 最大缓存时间immutable
: 资源不会变化,可永久缓存组合示例:
Cache-Control: public, max-age=3600, immutable
ETag
和 Last-Modified
的区别是什么?答:
ETag
是资源唯一标识符(如哈希值),更准确;Last-Modified
是时间戳,精度有限;ETag
更适合频繁小改动的资源;Last-Modified
更适合简单文件管理。答:
/app.abc123.js
Cache-Control: public, max-age=31536000, immutable
Vary
头?为什么重要?答:
Vary
告诉缓存服务器根据请求头区分缓存stale-while-revalidate
是什么?有什么作用?答:
Cache-Control
的扩展指令no-cache
和 no-store
的区别?答:
no-cache
:缓存可用,但必须先验证(发送请求给服务器)no-store
:禁止缓存,每次都请求服务器答:
s-maxage
、Vary
等控制答:
Cache-Control
、ETag
、Age
、X-Cache
curl -I
查看响应头答:
Cache-Control: no-cache
?t=123456
)绕过缓存HTTP 缓存是 Web 性能优化中不可或缺的一环。合理使用缓存可以显著提升页面加载速度、降低服务器负载、节省带宽成本。
掌握以下核心要点:
Cache-Control
是最强大的缓存控制手段ETag
比 Last-Modified
更精确Vary
处理差异化缓存深入理解 HTTP 缓存机制,是前端工程师、后端工程师、运维人员必备技能。
推荐阅读: