🧨 什么是“混存”?
混存 = 新版 HTML + 旧版 JS/CSS(或反过来)被用户混合加载
浏览器的缓存机制是在「加载前」就已经决定了,只有 HTTP 响应头能决定是否缓存。代码控制不了缓存行为,缓存完全由 HTTP 响应头 + CDN 配置 + 浏览器策略决定
混存场景:
-
发布了新版,JS 文件变成了 app.123abc.js
-
Cloudflare 还缓存着旧的 HTML(引用 app.789xyz.js)
-
用户访问时:
- HTML 是旧的(引用旧 JS)
- 旧的 JS 服务器已经删掉或改名了
-
⛔ 页面就加载不到脚本 → 白屏、功能异常,导致原因是多级缓存机制混战
关联性
绝不是单一环节导致的,而是「打包方式、Nginx 配置、CDN(如 Cloudflare)策略」这三者 联动不当 造成的
| 层级 | 缓存类型 | 控制手段 | 对项目的影响 |
|---|---|---|---|
| 1️⃣ 浏览器缓存 | 强缓存 / 协商缓存 | Cache-Control、ETag 等头 | 304 Not Modified 就来自这里 |
| 2️⃣ Cloudflare CDN 缓存-已处理 | 边缘节点缓存 | Page Rule / Cache Rule 等 | cf-cache-status: DYNAMIC/HIT/... |
浏览器 hearders 验证
这说明浏览器走了 协商缓存(Conditional Request),这时候 CF 的 CDN 缓存清除是无效的,因为走的是协商缓存
| 响应字段 | 值 | 含义说明 |
|---|---|---|
| cf-cache-status | DYNAMIC | ✅ 表示 Cloudflare 没有缓存这个请求,请求已直接回源 |
| 304 Not Modified | 浏览器本地命中 | ⚠️ 表示浏览器用了本地缓存,Cloudflare 已绕过但浏览器没绕过 |
| etag / last-modified | 存在 | 👉 属于浏览器的协商缓存机制 |
| 缓存层 | 是否主动控制 | 解决方式 |
|---|---|---|
| 浏览器缓存(强/协商) | ✅ 控制 Cache-Control、ETag 等响应头 | 在源站设置 |
| CDN 缓存(Cloudflare) | ✅ 通过 Page Rule / Cache Rule | 已配置 |
| HTML 指纹缓存 | ❌ HTML 没法指纹 | 必须设为 no-store-Nginx 配置 |
| 静态资源指纹缓存(JS/CSS) | ✅ Vite 已用 hash 文件名控制 | 已启用 |
混存的修改方案
-
【浏览器缓存】服务器上新增Nginx 配置,想相当于禁用协商缓存- 配置在https://xxxxx/ 下,配置前后观察成功率
# 禁止 HTML 缓存 location = /index.html { add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0" always; add_header Pragma "no-cache" always; add_header Expires 0 always; etag off; if_modified_since off; }* CDN / Cloudflare 配置(终端缓存层)-处理CDN 缓存
- 每次打包后,前端加入脚本-通过 CF 的 API 令牌,假设存在 CDN 配置方面的缓存,每次代码部署后,自动执行清除 bd.tpservice.vip的缓存脚本
Cache Level 使用「Standard」,确保遵循源站 Cache-Control 头 Page Rules 对 index.html 设置 Cache Level: Bypass Auto Minify / Rocket Loader (避免变更资源结构、引入隐性缓存)-已关 Always Online 关闭,避免拿旧内容兜底-已关
加入本地检测脚本观察,当前配置是否生效