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

Service Worker离线模式失效求助:缓存正常却无法离线运行

Service Worker离线失效及缓存重复问题排查修复

核心问题分析与修复步骤

1. 预缓存与运行时缓存命名冲突

  • 问题:代码中PRECACHE和RUNTIME使用了同一个缓存名precache-v1,导致预缓存资源和运行时缓存资源混存,引发重复缓存实例,还可能覆盖预缓存内容。
  • 修复:给RUNTIME设置独立的缓存名,比如runtime-v1。

2. Install事件未等待预缓存完成

  • 问题:cache.addAll(PRECACHE_URLS)未返回Promise,event.waitUntil无法等待所有资源缓存完成就执行skipWaiting(),导致部分资源可能未缓存成功。
  • 修复:在cache.addAll前添加return,确保Promise链完整,等待缓存操作全部完成。

3. 缓存URL路径不统一

  • 问题:PRECACHE_URLS中混合了相对路径(如/)和绝对路径(如http://localhost:8083/favicon.ico),页面发起的请求多为相对路径,导致caches.match无法匹配到绝对路径缓存的资源。
  • 修复:统一使用相对路径,将绝对路径资源改为相对路径,比如http://localhost:8083/favicon.ico改为/favicon.ico。

4. Service Worker中错误使用navigator对象

  • 问题:navigator.connection.onchange代码放在Service Worker文件中,但Service Worker全局环境没有navigator对象,会抛出错误影响SW正常运行。
  • 修复:将这段网络状态监听代码移到页面的JS文件中,而非SW文件。

5. Fetch事件未处理离线请求失败场景

  • 问题:当离线且缓存中无匹配资源时,fetch(event.request)会失败,浏览器会显示默认离线错误页。
  • 修复:添加fetch失败的捕获逻辑,返回自定义离线响应或 fallback 资源。

6. 注册代码兼容性判断优化

  • 问题:注册代码中navigator.serviceWorker的判断不够严谨,标准写法应先检查'serviceWorker' in navigator。
  • 修复:调整注册条件判断逻辑,同时添加注册成功/失败的日志便于排查。

修改后的Service Worker代码

// 缓存名称:预缓存和运行时缓存分开命名
var PRECACHE = 'precache-v1';
var RUNTIME = 'runtime-v1';

// 统一使用相对路径的预缓存资源列表
var PRECACHE_URLS = [
  '/',
  'pp-form.js',
  'pp-home.js',
  'pp.css',
  '/favicon.ico',
  '/operation/PO1',
  '/getForms/PO1/PF1',
  '/webjars/bootstrap-select/js/bootstrap-select.min.js',
  '/webjars/bowser/bowser.min.js'
];

self.addEventListener('install', function(event) {
  console.log('install');
  event.waitUntil(
    caches.open(PRECACHE)
      .then(function(cache){
        // 返回cache.addAll的Promise,确保等待缓存完成
        return cache.addAll(PRECACHE_URLS);
      })
      .then(self.skipWaiting())
  );
});

self.addEventListener('activate', function(event) {
    event.waitUntil(
        caches.keys().then(function(cacheNames){
            return Promise.all(
                cacheNames.map(function(cache){
                    // 清理非当前版本的预缓存和旧运行时缓存
                    if (cache !== PRECACHE && cache !== RUNTIME) {
                        return caches.delete(cache);
                    }
                })
            );
        })
        .then(function () {
            console.info("Old caches are cleared!");
            return self.clients.claim();
        })
    );
});

self.addEventListener('fetch', function(event) {
  console.log('fetch');
  // 处理同源请求
  if (event.request.url.startsWith(self.location.origin)) {
    event.respondWith(
      caches.match(event.request).then(function(cachedResponse) {
        // 缓存命中直接返回
        if (cachedResponse) {
          return cachedResponse;
        }

        // 缓存未命中则从网络请求,并存入运行时缓存
        return caches.open(RUNTIME).then(function(cache){
          return fetch(event.request).then(function(response) {
            // 仅缓存成功的响应(状态码200+或本地文件状态0)
            if (response.status === 200 || response.status === 0) {
              cache.put(event.request, response.clone());
            }
            return response;
          }).catch(function(error) {
            // 离线且无缓存时,返回自定义离线响应
            console.log('Fetch failed:', error);
            return new Response('当前离线且该资源未缓存', {
              status: 503,
              statusText: 'Service Unavailable'
            });
          });
        });
      })
    );
  }
});

修改后的注册代码

if ('serviceWorker' in navigator && (location.protocol === 'https:' || location.host.match(/(localhost|127.0.0.1)/))) {
  navigator.serviceWorker.register('/resources/pp-sw2.js')
    .then(function(registration) {
      console.log('Service Worker注册成功:', registration);
    })
    .catch(function(error) {
      console.log('Service Worker注册失败:', error);
    });
}

页面中的网络状态监听代码(移至页面JS)

if ('connection' in navigator) {
  navigator.connection.onchange = function(e) {
    console.log(navigator.onLine ? "已联网" : "已离线");
  };
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 09:25:59