为什么“指纹文件名”能触发更新
- 原理:构建产物的
.js/.css文件名里包含内容哈希(如index-CGIWmfc8.js)。只要代码变更,哈希就变,新文件名也变。 - 流程:
- 浏览器先请求
index.html; index.html内引用了带新哈希的资源 URL;- 浏览器发现是“从未见过”的新文件名,必然重新下载新资源(不会命中旧缓存)。
- 浏览器先请求
- 关键点:要让浏览器“拿到最新的 index.html”,否则它就不知道有新的哈希文件名。
为什么 HTML 建议 no-cache,而静态资源建议长缓存
- HTML(入口):
- 作用:它是“目录索引”,负责告诉浏览器最新的资源文件名。
- 策略:设置 Cache-Control 为 “no-cache” 或者“短缓存 + ETag/Last-Modified”,让浏览器每次(或很快)向服务器验证新旧。
- 含义:no-cache 不是“不缓存”,而是“每次用前先和服务器确认是否有更新”(条件请求,命中则 304)。
- 静态资源(.js/.css/字体/图片):
- 作用:体积大、数量多;文件名带哈希,内容变更才会换名。
- 策略:可设置超长缓存,如 1 年,并加
immutable。因为一旦内容变更,文件名会变,不会与旧缓存冲突。 - 好处:加速加载、减少带宽与服务器压力。
Nginx 实践配置 示例
- HTML:启用协商缓存,或直接 no-cache
# 根路径或 HTML
location = / {
add_header Cache-Control "no-cache";
# 或者短缓存 + must-revalidate
# add_header Cache-Control "max-age=60, must-revalidate";
}
location ~* \.html$ {
add_header Cache-Control "no-cache";
# 可选:确保有 ETag/Last-Modified,nginx 默认发送 Last-Modified
# etag on; #(多数版本默认开启,可视版本情况)
}
- 静态资源:长缓存 + immutable(仅对带哈希命名的产物生效)
# 带哈希产物所在目录(按你的部署路径调整)
location /assets/ {
# 强缓存 1 年
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
# 确保不对这些资源做额外改写
try_files $uri =404;
}
- 注意:如果你的静态资源不带哈希(如某些图片),不要给它们设置 immutable 的超长缓存,否则更新会困难。
可替代/补充策略
- 严格不缓存 HTML:
Cache-Control: no-store(最保守,次次强制获取最新 HTML;代价是请求次数更多)。 - 短缓存 HTML:
Cache-Control: max-age=60, must-revalidate(1 分钟内直接用,过期后协商校验;兼顾性能与时效)。 - CDN/代理一致性:CDN 也要对路径类型分别配置缓存策略,避免覆盖源站策略。
如何验证
- 用 curl 看响应头是否符合预期:
# HTML
curl -I https://你的域名/index.html
# 某个构建后的 js/css
curl -I https://你的域名/assets/index-CGIWmfc8.js
- 在浏览器 DevTools → Network:
- 刷新页面,查看
index.html是否显示from disk cache/from memory cache或status 304(命中协商缓存)。 - 查看
.js/.css是否带Cache-Control: public, max-age=31536000, immutable。
- 刷新页面,查看
- 发布新版本后:
index.html应该很快拿到新内容(或经验证返回 304 未改动)。- 引用的资源文件名变了,浏览器会请求新
.js/.css文件,完成更新。
常见坑
- HTML 被意外长缓存:用户一直拿不到最新
index.html,看不到新文件名,导致前端不更新。 - 静态资源没用哈希命名:即便文件内容变了,文件名不变,长缓存会让用户继续用老资源。
- CDN 覆盖源策略:CDN 把 HTML 也长缓存了,发布后用户仍拿旧 HTML。
这样配置后,发布新版本时只要替换 index.html 与新指纹资源,浏览器就会在下一次刷新或访问时感知到新版本并拉取新资源,既保证时效,又保证性能。