html缓存策略需设no-cache或max-age=0,must-revalidate,静态资源须用哈希文件名+public,max-age=31536000,含用户态内容不可整页静态化,etag须由服务端基于响应体生成。

HTML 本身不是性能瓶颈,但它的写法和缓存配置共同决定了首屏加载是否可靠、更新是否及时、CDN 是否真能生效。错配缓存头或滥用内联脚本,会让所有后端优化失效。
HTML 响应头必须设 no-cache 或 max-age=0, must-revalidate
很多人给 index.html 加 Cache-Control: public, max-age=3600,结果上线后用户半天看不到新按钮——因为浏览器直接用了本地旧 HTML,连请求都没发。
-
no-cache表示每次都要向服务端验证(发If-None-Match),服务端返回304 Not Modified就复用本地副本,既省带宽又保一致 -
max-age=0, must-revalidate更明确:允许缓存,但强制校验;比max-age=0单独用更稳妥,避免某些客户端降级为no-store - Nginx 配置示例:
location = /index.html { add_header Cache-Control "no-cache"; } - 绝对不要用
immutable给 SSR 入口页或含动态路由的 HTML——它假设内容永不变,现实里文案、跳转链接、AB 实验开关都可能随时改
静态资源(JS/CSS/图片)必须用哈希文件名 + public, max-age=31536000
HTML 缓存策略再严谨,如果它引用的 main.js 每次都重新下载,首屏照样卡顿。关键不在 HTML 本身,而在它拉的资源是否真正可缓存。
- Webpack/Vite 构建时启用
contenthash,生成类似main.ea7f2d.js的文件名;URL 变了,浏览器自然走新缓存 - 响应头设
Cache-Control: public, max-age=31536000,告诉 CDN 和浏览器“这个文件一年内不会变” - CMS 上传的图片无法自动加哈希?那就靠
ETag或Last-Modified协商缓存,别硬塞max-age=0 -
<meta http-equiv="Cache-Control">在现代浏览器中无效,别白费劲
含用户态内容的页面不能整页静态化,否则会缓存错乱
把登录态欢迎语、购物车数量、实时评论这些变量塞进一个预生成的 user_profile_123.html,等于把多用户上下文压进单个缓存 key——结果 A 用户看到 B 用户的昵称,C 用户的订单数显示为 0。
- 真正适合静态化的,是无用户上下文、读多写少的内容:商品详情页(不含“已加入购物车”按钮)、帮助文档、活动规则页
- 含用户态的区域,要么用 ESI(Edge Side Includes)做边缘组装,要么前端 JS 动态注入;强行静态化只会引入更多兜底逻辑和调试成本
- 如果非要用模板碎片缓存,key 必须包含可变维度:如
fragment:header:user_id=456:lang=zh,而不是简单按文件名缓存 - 避免缓存含内联
<script></script>的片段——SSR 渲染后 script 会重复执行,且无法随客户端状态更新
ETag 协商必须配合服务端可控生成,禁用 Nginx 默认 mtime+size
默认的 Nginx ETag 基于文件修改时间和大小,但 HTML 是 SSR 输出或模板拼接生成的,文件没变不代表内容没变——比如数据库里 Banner 文案改了,但 index.html 文件时间戳没更新,ETag 就不会变,协商永远返回 304。
- 关掉默认 ETag:
etag off; - 让后端在响应头中输出基于响应体哈希的
ETag,例如ETag: "W/"abc123"" - Nginx 配置里别写
add_header ETag ""—— 这会触发 Nginx 自己算,还是回到mtime+size老路 - 验证是否生效?只看 Network 面板里 HTML 请求的 Status:出现
304 Not Modified才算真协商成功;200 OK且有ETag头是首次或内容真变了
最常被忽略的点:HTML 缓存策略不是独立配置项,它和构建流程、部署方式、CDN 版本控制强耦合。比如 CI/CD 发布时没清 CDN 缓存,或静态文件写到了本地磁盘而非共享存储,再好的 Cache-Control 也救不回 404 或脏数据。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











