多级缓存导致前端白屏的本质原因与系统性解决方案

156 阅读2分钟

🧨 什么是“混存”?

混存 = 新版 HTML + 旧版 JS/CSS(或反过来)被用户混合加载

浏览器的缓存机制是在「加载前」就已经决定了,只有 HTTP 响应头能决定是否缓存。代码控制不了缓存行为,缓存完全由 HTTP 响应头 + CDN 配置 + 浏览器策略决定

混存场景:

  1. 发布了新版,JS 文件变成了 app.123abc.js

  2. Cloudflare 还缓存着旧的 HTML(引用 app.789xyz.js)

  3. 用户访问时:

    • HTML 是旧的(引用旧 JS)
    • 旧的 JS 服务器已经删掉或改名了
  4. ⛔ 页面就加载不到脚本 → 白屏、功能异常,导致原因是多级缓存机制混战

关联性

绝不是单一环节导致的,而是「打包方式、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-statusDYNAMIC✅ 表示 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关闭,避免拿旧内容兜底-已关

加入本地检测脚本观察,当前配置是否生效