You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何防止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,不用手动改版本号

验证步骤

  1. 发新版本后,先清自己浏览器缓存,访问页面
  2. 普通刷新,看Network面板里的资源是不是最新版本
  3. 找没访问过新版本的用户直接访问,确认不用强制刷新就能加载新内容

内容的提问来源于stack exchange,提问作者Davide Paolillo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 05:05:06