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

如何通过Service Worker实现带参数动态页面的离线缓存?

问题分析与解决方案

核心问题诊断

你遇到的问题主要源于对Service Worker(SW)注册规则和缓存逻辑的误解:

  1. 单域名同一作用域仅能激活一个SW:你通过带event参数的offlineWorker.js.php注册多个SW,会导致后续注册的SW覆盖之前的,旧SW创建的缓存无法被新SW识别,自然无法离线返回页面。
  2. 带参数的SW注册存在作用域冲突:SW的默认作用域是其脚本所在的路径,即使你给SW URL加了参数,只要脚本在同一目录(/myevents/),所有SW的作用域都是/myevents/,新注册的SW会直接替换旧的。
  3. 缓存路径支持URL参数,但需匹配完整请求:缓存可以存储带参数的URL,但你的多SW方案中,新SW无法读取旧SW创建的缓存条目,导致页面缓存失效。

正确解决方案:单个SW处理所有Event页面缓存

不要创建多个SW,用单个SW统一拦截所有带event参数的dataEntry.php请求,为每个event生成独立缓存条目。

步骤1:注册单个无参数的Service Worker

在菜单页或dataEntry.php中加入注册代码(确保所有用户访问时都会触发注册):

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/myevents/offlineWorker.js')
      .then(reg => console.log('SW注册成功:', reg.scope))
      .catch(err => console.error('SW注册失败:', err));
  });
}

步骤2:编写统一的Service Worker逻辑(offlineWorker.js)

这个SW会为每个event单独缓存页面,同时复用静态资源缓存:

// 缓存命名前缀,区分静态资源和各Event页面
const CACHE_STATIC = 'event-static-assets';
const CACHE_PREFIX = 'event-data-entry-';
// 预缓存的静态资源(比如你的CSS)
const STATIC_ASSETS = ['/myevents/styles.css'];

// 安装阶段:缓存静态资源
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_STATIC)
      .then(cache => cache.addAll(STATIC_ASSETS))
      .then(() => self.skipWaiting()) // 强制激活新SW
  );
});

// 激活阶段:清理过期缓存
self.addEventListener('activate', (event) => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.filter(name => {
          // 清理旧的Event页面缓存,保留静态资源缓存
          return name.startsWith(CACHE_PREFIX) && name !== CACHE_STATIC;
        }).map(name => caches.delete(name))
      );
    }).then(() => self.clients.claim()) // 接管所有已打开的页面
  );
});

// 拦截请求,处理缓存逻辑
self.addEventListener('fetch', (event) => {
  const requestUrl = new URL(event.request.url);

  // 处理带event参数的dataEntry.php请求
  if (requestUrl.pathname === '/myevents/dataEntry.php' && requestUrl.searchParams.has('event')) {
    const eventId = requestUrl.searchParams.get('event');
    const eventCacheName = `${CACHE_PREFIX}${eventId}`;

    event.respondWith(
      caches.match(event.request) // 匹配完整请求(含参数)
        .then(cachedRes => {
          // 有缓存直接返回
          if (cachedRes) return cachedRes;

          // 无缓存则请求网络,并存入对应Event的缓存
          return fetch(event.request)
            .then(networkRes => {
              caches.open(eventCacheName)
                .then(cache => cache.put(event.request, networkRes.clone()));
              return networkRes;
            });
        })
    );
  }
  // 处理静态资源请求(复用缓存)
  else if (STATIC_ASSETS.includes(requestUrl.pathname)) {
    event.respondWith(
      caches.match(event.request)
        .then(cachedRes => cachedRes || fetch(event.request))
    );
  }
});

关键逻辑说明

  • 缓存隔离:每个event对应独立的缓存(命名为event-data-entry-2024abcd),确保不同Event的页面缓存互不干扰。
  • 完整请求匹配:缓存时使用包含event参数的完整请求URL,保证离线时能精准匹配到对应的页面。
  • 静态资源复用:CSS等静态资源单独缓存,所有Event页面共享,减少冗余缓存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 08:52:21