发布后部分用户白屏,报 ChunkLoadError
新版本上线十分钟,客服收到反馈:一部分用户打开是白屏,清缓存后又正常。
现象
控制台报懒加载分块失败,只有部分用户、部分地区出现:
Uncaught ChunkLoadError: Loading chunk 12 failed.
(missing: https://cdn.example.cn/gis/js/12.8a4f1c2e.js)
at __webpack_require__.e (bootstrap:64)
被引用的分块文件名在 CDN 上返回 404,但服务器源站上确实存在新文件。 同一时间刷新多次,偶尔又能打开。
原因
分块文件名带 hash,每次发布会换。用户手里是旧版 index.html,
它指向旧的分块;旧分块在发布时被清理,请求就 404。
HTML 被 CDN 或浏览器缓存得越久,命中的概率越高。
多节点 CDN 回源不一致时,还会出现“这个节点有新文件、那个节点还是旧索引”的混合状态。
排查过程
- 看
index.html的响应头,Cache-Control是否为长缓存。 - 对比 CDN 上 HTML 引用的分块名与源站实际文件名。
- 用不同地区节点请求同一 HTML,比较
ETag与内容。
curl -I https://cdn.example.cn/gis/index.html
# Cache-Control: public, max-age=86400 ← HTML 被缓存一天,问题根源
curl -s https://cdn.example.cn/gis/index.html | grep -o 'js/[0-9a-f]*\.js'
解决方案
HTML 必须不缓存或极短缓存,带 hash 的静态资源才可以长缓存:
location = /gis/index.html {
add_header Cache-Control "no-store, no-cache, must-revalidate";
add_header Pragma "no-cache";
}
location /gis/js/ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
发布时不要立刻删除旧分块,保留一到两个版本,给已经打开页面的用户留出切换窗口:
# 构建产物按版本目录存放,软链接指向当前版本
/var/www/gis/releases/20261029/js/12.8a4f1c2e.js
/var/www/gis/releases/20261022/js/12.7b3e9d1f.js # 保留上一版
前端加一层兜底:捕获分块加载失败后自动刷新一次,避免用户停在白屏:
window.addEventListener('unhandledrejection', function (e) {
var msg = String(e.reason && e.reason.message || '');
if (msg.indexOf('ChunkLoadError') > -1 || msg.indexOf('Loading chunk') > -1) {
if (!sessionStorage.getItem('chunk-reloaded')) {
sessionStorage.setItem('chunk-reloaded', '1');
location.reload();
}
}
});
验证
index.html 响应头包含 no-store,刷新后拿到最新内容。
发布新版本后,旧页面继续操作不会 404;新打开的页面加载的是新分块。
不同地区节点请求 HTML 内容一致。
缓存策略只有一条原则:入口文件不缓存,带 hash 的资源永久缓存。 反过来配,必然出现新旧混用。
经纬志(2026)。《发布后部分用户白屏,报 ChunkLoadError》。https://www.jingweizhi.com/cookbook/cdn-static-cache.html(访问日期 2026-11-03)。