HTML入口文件必须禁用强缓存,因多语言HTML内容动态变化,服务端需返回Cache-Control: no-cache, must-revalidate;静态资源须加contenthash并配immutable;语言JSON按发布节奏设max-age=3600+must-revalidate;Service Worker不应缓存HTML。

HTML入口文件必须禁用强缓存,不能靠控制
所有国际化 HTML 入口(如 index.html、zh-CN.html、en-US.html)都属于动态路由或 SSR 渲染起点,内容随语言、用户身份、地区实时变化。一旦配置了 Cache-Control: public, max-age=3600,浏览器就会跳过验证直接复用旧副本——结果是用户切换语言后仍看到上一个 locale 的 DOM,或者登录态未更新导致按钮错乱、文案残留。
关键点在于:<meta http-equiv="Cache-Control" content="no-cache"> 在 Chrome/Firefox/Edge 中完全无效,它不触发 If-None-Match 请求,也不影响缓存决策。真正起效的只有服务端返回的 HTTP 响应头。
- Nginx 配置示例(针对多 locale 入口):
location ~* ^/(index|zh-CN|en-US|ja-JP)\.html$ { add_header Cache-Control "no-cache, must-revalidate, max-age=0"; add_header ETag ""; expires epoch; } - 若使用 Express,需在对应路由中显式设置:
res.set('Cache-Control', 'no-cache, must-revalidate') - CDN(如 Cloudflare、Vercel)必须关闭“自动缓存 HTML”开关,并通过规则匹配
/**/*.html强制覆盖为短缓存
静态资源(JS/CSS/图片)必须绑定内容哈希 + immutable
国际化项目里,main.js 可能被 zh-CN.html 和 en-US.html 同时引用,但不同语言包对应的翻译 chunk 内容不同。如果 JS 文件名不变,而构建产物内容变了,浏览器却因强缓存继续加载旧版本,就会出现「中文页面显示英文文案」或「按钮点击无响应」这类错配问题。
解决方式不是给 JS 加长缓存时间,而是让 URL 本身携带内容指纹:
立即学习“前端免费学习笔记(深入)”;
- Webpack/Vite 构建时启用
contenthash:输出类似main.ea7f2d.js、locales/zh-CN.8c3b1a.json - Nginx 配置匹配静态资源扩展名:
location ~* \.(js|css|json|woff2|png|jpg|gif)$ { expires 1y; add_header Cache-Control "public, immutable"; } -
immutable很关键:它告诉浏览器“这个 URL 永远不会变内容”,后续访问可跳过If-None-Match请求,省掉一次 RTT;但如果没加哈希就配immutable,反而锁死旧资源
语言资源文件(JSON/PO)的缓存要区分场景
前端 i18n 库(如 i18next、vue-i18n)常通过 AJAX 加载 /locales/zh-CN.json 这类语言包。这类文件变动频率介于 HTML 和 JS 之间:比 HTML 稳定,但又不如打包后的 JS 长期不变。盲目设 max-age=31536000 容易导致翻译更新延迟上线;设 no-cache 又浪费带宽。
推荐按发布节奏分级处理:
- 构建时内联核心语言字段(如导航栏、按钮),避免额外请求
- 动态加载的 locale JSON 文件,设
Cache-Control: public, max-age=3600, must-revalidate—— 允许缓存 1 小时,但每次用前校验 ETag - 若使用 CDN,确保其未覆盖源站的
ETag或Last-Modified头;否则协商缓存失效,变成全量重拉 - 避免在 URL 中拼 query 参数(如
zh-CN.json?v=2.1),这会绕过浏览器对同一 URL 的缓存合并逻辑
Service Worker 缓存 HTML 要小心版本漂移
有些团队用 Service Worker 主动缓存 index.html 实现离线支持,但在多语言场景下极易出错:SW 缓存的是某次 fetch 到的 HTML 快照,而该快照可能绑定了特定 locale 的 JS chunk hash。当新版本部署后,HTML 更新了,但 SW 里的旧 HTML 仍试图加载已删除的 main.oldhash.js,结果白屏或报 404。
除非你实现完整的版本映射和回滚机制,否则更稳妥的做法是:
- SW 不缓存任何 HTML 文件,只缓存静态资源(JS/CSS/图片/语言 JSON)
- 对 HTML 请求始终 bypass:
if (event.request.destination === 'document') return; - 若必须缓存 HTML,需在每次构建后生成唯一 SW 版本号,并强制更新,同时配套清理旧 cache storage —— 这增加了发布复杂度,多数项目不值得
真正容易被忽略的是:国际化缓存策略不是单点配置问题,而是 HTML、JS、JSON、CDN、SW 五者联动的结果。任何一个环节缓存周期不匹配,都会导致语言错乱、资源 404 或白屏。最脆弱的一环永远是 HTML 入口 —— 它不缓存,首屏慢;缓存错了,整个应用就不可用。



















