单靠 Cache-Control 或 Expires 远远不够,必须组合服务端缓存(Nginx/Varnish)、客户端强制缓存与协商缓存策略;否则高并发下易发生缓存雪崩、CDN/Nginx 忽略响应头、移动端兼容性问题及多层缓存配置错位导致整体失效。

直接说结论:对高访问量页面,仅靠 Cache-Control 或 Expires 做浏览器端缓存远远不够;必须分层组合——服务端缓存(如 Nginx / Varnish) + 客户端强制缓存 + 合理的协商缓存策略,三者缺一不可。
为什么单靠 Cache-Control: public, max-age=3600 会失效
高并发下,大量请求在缓存过期瞬间同时击穿到后端,造成“缓存雪崩”。即使设置了 1 小时有效期,若页面每秒被请求 500 次,而缓存恰好在整点全部失效,后端将瞬间承受 180 万次/小时的原始请求压力。
更关键的是:max-age 只控制浏览器行为,不阻止 CDN 或反向代理(如 Nginx)的二次判断。如果 Nginx 没配 proxy_cache_valid,它可能忽略你响应头里的 Cache-Control,自己按默认规则缓存或不缓存。
- 浏览器看到
max-age=3600,确实会在 1 小时内跳过请求 - 但 CDN 节点、公司内网反向代理、甚至某些运营商网关,可能根本不认这个头,或只认
Expires - 移动端 WebView(尤其 Android 旧版)对
Cache-Control解析有兼容性 bug,容易降级为每次请求
nginx proxy_cache 必须手动开启且精细配置
Nginx 默认完全不启用缓存,哪怕你返回了完美的 Cache-Control 头。必须显式配置缓存区、缓存键、生命周期和绕过逻辑。
典型漏配项:
- 没设置
proxy_cache_path—— 缓存根本无处存放 - 没用
proxy_cache_key排除用户 Cookie 或随机参数(如utm_source),导致同一页面被缓存 N 份 - 没配
proxy_cache_valid 200 301 302 1h—— Nginx 可能只缓存 5 分钟,无视你响应头 - 没加
proxy_ignore_headers Cache-Control Expires—— 这行反而要慎用:它会让 Nginx 强制忽略后端头,改用自己规则;但若你信任后端控制权,就不该加
一个安全起点配置片段:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m inactive=60m;
server {
location /news/ {
proxy_cache my_cache;
proxy_cache_valid 200 301 302 1h;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_pass http://backend;
}
}
静态资源与 HTML 页面必须区分缓存策略
把 index.html 和 main.css?v=2.3.1 用同一套缓存规则是常见错误。HTML 页面通常需短周期强验证,CSS/JS 则可长期强缓存。
正确做法:
- HTML 页面:设
Cache-Control: public, max-age=60, must-revalidate—— 浏览器 1 分钟内直取缓存,过期后必须发请求校验(触发ETag或Last-Modified协商) - CSS/JS/图片:用内容哈希命名(如
app.a1b2c3d4.js),再设Cache-Control: public, max-age=31536000, immutable—— 浏览器永久缓存,除非 URL 改变 - 避免给 HTML 加
immutable:HTML 内容常变,但 URL 不变,加了会导致用户永远看不到更新
注意:immutable 是 HTTP/1.1 扩展指令,Chrome 49+、Firefox 49+ 支持,Safari 目前不支持,但无害回退。
协商缓存不是“备选方案”,而是高并发下的安全阀
当页面无法做长周期强缓存(比如含用户未读消息数),ETag 比 Last-Modified 更可靠:后者只能精确到秒,高并发下同一秒内多次发布会导致校验失效,引发误刷新。
实操要点:
- 生成
ETag应基于响应体哈希(如md5(html_output)),而非文件修改时间 - 确保后端在计算 ETag 时,排除动态插入的毫秒级时间戳、随机 nonce 等干扰项
- 不要在 HTML 中混用
ETag和Cache-Control: no-cache—— 后者会禁用强制缓存,让每次请求都走协商,白白增加 RTT
真正棘手的点在于:缓存决策分散在浏览器、CDN、反向代理、源站四层,任意一层配置错,都会让其他层的努力白费。调试时务必用 curl -I 逐层看响应头,而不是只信开发者工具 Network 面板里显示的最终结果。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











