如何防止Unity WebGL构建文件被浏览器永久缓存?
Unity WebGL 更新后浏览器顽固缓存旧资源的解决方案
问题背景
我们把Unity WebGL构建部署在Aruba服务器上,每次发新版本(删旧文件换新构建)后,浏览器会死死缓存旧文件。用户必须强制刷新才能拿到新版本,但普通刷新又会重新加载旧文件,导致每次访问都得搞强制刷新才行。
我们要保留缓存保证加载速度,同时更新时浏览器能自动检测并加载新版本。试过给资源URL加版本号(?v=1.0.5)但没用,也考虑过禁用Unity数据缓存,但那样加载时间根本没法接受。
当前实现代码
<!DOCTYPE html> <html lang="en-us"> <head> <meta charset="utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> ... <script src="Build/EyeRidersX.loader.js?v=1.0.5"></script> <link rel="stylesheet" href="TemplateData/style.css"> <link rel="manifest" href="manifest.webmanifest"> ... </head> <body> <div id="unity-container"> <canvas id="unity-canvas" width=960 height=600></canvas> <div id="unity-loading-bar"> <div id="unity-logo"></div> <div id="unity-progress-bar-empty"> <div id="unity-progress-bar-full"></div> </div> </div> <div id="unity-warning"> </div> </div> <!-- 注意:代码里有重复的DOM元素,建议清理掉 --> <div id="unity-progress-bar-full"></div> </div> </div> <div id="unity-warning"> </div> </div> <script> window.addEventListener("load", function () { if ("serviceWorker" in navigator) { navigator.serviceWorker.register("ServiceWorker.js"); } }); var container = document.querySelector("#unity-container"); var canvas = document.querySelector("#unity-canvas"); var loadingBar = document.querySelector("#unity-loading-bar"); var progressBarFull = document.querySelector("#unity-progress-bar-full"); var warningBanner = document.querySelector("#unity-warning"); function unityShowBanner(msg, type) { function updateBannerVisibility() { warningBanner.style.display = warningBanner.children.length ? 'block' : 'none'; } var div = document.createElement('div'); div.innerHTML = msg; warningBanner.appendChild(div); if (type == 'error') div.style = 'background: red; padding: 10px;'; else { if (type == 'warning') div.style = 'background: yellow; padding: 10px;'; setTimeout(function() { warningBanner.removeChild(div); updateBannerVisibility(); }, 5000); } updateBannerVisibility(); } var buildUrl = "Build"; var loaderUrl = buildUrl + "/EyeRidersX.loader.js?v=1.0.5"; var config = { dataUrl: buildUrl + "/EyeRidersX.data?v=1.0.5", frameworkUrl: buildUrl + "/EyeRidersX.framework.js?v=1.0.5", codeUrl: buildUrl + "/EyeRidersX.wasm?v=1.0.5", streamingAssetsUrl: "StreamingAssets", ... productVersion: "1.1.1", showBanner: unityShowBanner, }; ... </script> </body> </html>
解决思路与实操方案
1. 先搞定服务器缓存配置(版本号失效的核心原因)
你加了?v=xxx但没用,大概率是Aruba服务器给静态资源设了超长缓存时间,而且没把URL里的版本号当回事。得这么配:
- 给Unity核心文件(
.js、.data、.wasm)设Cache-Control: public, max-age=31536000, must-revalidate——既长期缓存省加载时间,又能在资源变化时触发更新 - 要求服务器把URL里的查询参数(
?v=1.0.5这类)当作缓存标识,不同版本号的资源算不同文件 - 入口HTML文件必须设
Cache-Control: no-cache, no-store, must-revalidate——保证用户每次打开页面都拿到最新的HTML,这样才能加载带新版本号的资源
2. 补全所有资源的版本号
当前代码里style.css、manifest.webmanifest和ServiceWorker.js没加版本号,这些文件被缓存也会导致更新失效,补上:
<!-- 修改后 --> <link rel="stylesheet" href="TemplateData/style.css?v=1.0.5"> <link rel="manifest" href="manifest.webmanifest?v=1.0.5"> <script> window.addEventListener("load", function () { if ("serviceWorker" in navigator) { // 给ServiceWorker也加版本号 navigator.serviceWorker.register("ServiceWorker.js?v=1.0.5"); } }); </script>
3. 处理ServiceWorker的独立缓存
如果用了ServiceWorker,它会自己存资源,和浏览器缓存不互通。新版本发布时要更新ServiceWorker的版本号,并在激活时清理旧缓存:
// ServiceWorker.js示例 const CACHE_VERSION = 'v1.0.5'; const CACHE_NAME = `unity-cache-${CACHE_VERSION}`; self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE_NAME).then((cache) => { // 缓存带版本号的资源 return cache.addAll([ '/', '/TemplateData/style.css?v=1.0.5', '/Build/EyeRidersX.loader.js?v=1.0.5', // 其他需要缓存的资源... ]); }) ); // 立即激活新的ServiceWorker self.skipWaiting(); }); self.addEventListener('activate', (event) => { event.waitUntil( caches.keys().then((cacheNames) => { // 删除所有旧版本的缓存 return Promise.all( cacheNames.filter((name) => !name.includes(CACHE_VERSION)) .map((name) => caches.delete(name)) ); }) ); // 让新ServiceWorker接管所有客户端 self.clients.claim(); });
4. 用Unity自动生成哈希文件名(最省心的方案)
Unity WebGL支持构建时自动给资源文件加哈希后缀(比如EyeRidersX.data.abc123),文件内容变了哈希自动更新,比手动加版本号靠谱多了:
- 打开Unity编辑器,进
Player Settings > WebGL > Optimization - 勾选
Enable Hash File Names - 构建后,Unity生成的HTML会自动用带哈希的资源URL,不用手动改版本号
验证步骤
- 发新版本后,先清自己浏览器缓存,访问页面
- 普通刷新,看Network面板里的资源是不是最新版本
- 找没访问过新版本的用户直接访问,确认不用强制刷新就能加载新内容
内容的提问来源于stack exchange,提问作者Davide Paolillo
相关产品推荐
相关产品推荐

