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

Service Worker无法从缓存返回文件问题求助

问题分析与解决方案

看起来你的问题核心在于**fetch事件中没有为所有请求返回合法的Response对象**,同时缓存匹配的逻辑也有疏漏,直接导致浏览器抛出了「传递的不是Response对象」的错误。咱们一步步拆解问题并修复:

1. 直接触发报错的根源:非法的Promise处理

你在缓存匹配失败时写了reject('no result'),这是错误的——evt.respondWith()要求传入的Promise必须解析为一个Response对象,而不是字符串类型的拒绝值。当非根路径的请求(比如/js/script.js)缓存匹配失败后,会进入catch分支,但你的catch只处理了根URL的情况,其他请求走到这里没有返回任何合法响应,直接触发了浏览器的错误提示。

2. 缓存匹配的潜在路径问题

你提到缓存存储里文件正常但匹配不到,大概率是缓存路径与请求URL的匹配规则导致的:

  • 如果你预缓存的是相对路径(比如js/script.js),而请求的是完整绝对URL(https://myurl.com/js/script.js),caches.match(evt.request)默认是可以匹配的,但有时候需要明确解析URL的路径部分来确保匹配准确。

修复后的完整代码

下面是调整后的逻辑,兼顾了SPA路由需求(所有页面路由返回index.html)和缓存优先的核心策略:

// 缓存名称带版本号,方便发布新版本时更新缓存
const CACHE = 'my-app-cache-v1';

function precache() {
  return caches.open(CACHE).then(function(cache) {
    return cache.addAll([
      '/index.html', // 统一用绝对路径开头,避免不同页面下的路径歧义
      '/js/script.js',
      '/img/bg.png',
      '/img/logo.svg',
      // ...其他需要预缓存的文件
    ]);
  });
}

self.addEventListener('fetch', function(evt) {
  evt.respondWith(
    caches.match(evt.request)
      .then(function(response) {
        // 缓存命中,直接返回资源
        if (response) {
          return response;
        }

        // 处理SPA路由:所有同源的页面请求都返回index.html
        const requestUrl = new URL(evt.request.url);
        if (requestUrl.origin === location.origin) {
          return caches.match('/index.html');
        }

        // 非同源/非页面请求的兜底:返回404或走网络(根据你的需求调整)
        return new Response('Resource not found in cache', { status: 404 });
      })
      .catch(function(error) {
        // 缓存匹配出错时的兜底,确保返回合法响应
        console.error('Cache match failed:', error);
        return caches.match('/index.html');
      })
  );
});

关键优化点说明

  • 移除非法的reject('no result'):确保每个分支都返回合法的Response对象,彻底解决浏览器报错问题。
  • 统一预缓存路径:所有路径以/开头,避免相对路径在不同页面下的歧义。
  • SPA路由适配:通过解析请求URL的origin,确保所有同源页面请求都返回index.html,符合单页应用的路由逻辑。
  • 错误兜底机制:在catch分支统一返回index.html,避免出现无响应的情况。

版本更新的补充逻辑

当发布新版本时,记得修改CACHE的版本号(比如从v1改成v2),同时在activate事件中清理旧缓存,确保用户加载到最新资源:

self.addEventListener('activate', function(evt) {
  evt.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.filter(function(cacheName) {
          // 删除旧版本缓存
          return cacheName !== CACHE;
        }).map(function(cacheName) {
          return caches.delete(cacheName);
        })
      );
    })
  );
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:38:31