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

Service Worker缓存HTML页面失败 访问报ERR_FAILED错误

问题现象

未通过Service Worker将页面加入缓存时,页面跳转访问无异常;将目标页面加入缓存列表后,无论在线、离线环境均无法访问对应页面,该问题仅出现在页面类HTML资源上,.jpg、.png、.js、.css及公共HTML片段(如导航栏、页脚)等资源的缓存、访问均正常。

故障复现场景

将页面加入缓存后跳转至对应页面时,浏览器返回错误:无法访问站点,位于页面链接的网页可能暂时无法访问,或是已永久移动到新的web地址,错误码:ERR_FAILED。

当前Service Worker实现代码
const staticChacheName = 'site-static'
const assets = [
    '/',
    '/index.html',
    '/Html/Elements/footer.html',
    '/Html/Elements/mobile_menu.html',
    '/Html/Elements/navbar.html',
    '/Html/Pages/film.html',          //not working
    '/Html/Pages/anime.html',         //not working
    '/Html/Pages/sitobello.html',     //not working
    '/Html/Pages/song.html',          //not working
    '/Html/Pages/amici_home.html',    //not working
    '/Html/Pages/Amici/tilde.html',   //not working
    '/Html/Pages/Amici/kloe.html',    //not working

    'Css/Index/style.css',
    'Css/Sito Bello/background.css',
    'Css/Sito Bello/section.css',
    'Css/Sito Bello/settings.css',
    'Css/Song/background.css',
    'Css/Song/elementi.css',
    'Css/Film/background.css',
    'Css/Film/elementi.css',
    'Css/Anime/background.css',
    'Css/Anime/elementi.css',
    'Css/Element/footer.css',
    'Css/Element/mobile_menu.css',
    'Css/Element/navbar.css',
    'Css/Element/scrollbar.css',
    'Css/Amici/Home/background.css',
    'Css/Amici/Home/elementi.css',
    'Css/Amici/Kloe/background.css',
    'Css/Amici/Tilde/background.css',

    '/Images/Logo.png',
    '/Images/Index/background.jpg',

    '/Javascript/Element/navbar.js',
    '/Javascript/Film/add.js',
    '/Javascript/Sito Bello/add.js',
    '/Javascript/Sito Bello/settings.js',

    '/manifest.webmanifest',
    '/Javascript/app.js',
]

//install service worker
self.addEventListener('install', evt => {
    evt.waitUntil(
        caches.open(staticChacheName).then(chache => {
            console.log('chaching shell assets')
            chache.addAll(assets)
    }))
})

//activate service worker
self.addEventListener('activate', evt => {
})

self.addEventListener('fetch', evt => {
    evt.respondWith(
        caches.match(evt.request).then(chacheRes => {
            return chacheRes || fetch(evt.request)
        })
    )
})
故障页面示例(以film.html为例)
<!DOCTYPE html>
<html lang="it">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css">
        <link rel="stylesheet" href="/Css/Element/navbar.css">
        <link rel="stylesheet" href="/Css/Element/mobile_menu.css">
        <link rel="stylesheet" href="/Css/Film/background.css">
        <link rel="stylesheet" href="/Css/Film/elementi.css">
        <link rel="stylesheet" href="/Css/Element/footer.css">
        <link rel="stylesheet" href="/Css/Element/scrollbar.css">
        <link rel="manifest" href="/manifest.webmanifest">
        <link rel = "icon" href = "/Images/Logo.png" type = "image/x-icon">
        <title>Aside - Film</title>
    </head>

    <body>

        <nav></nav>
        <div id="mb-menu"></div>

        <h1 id="title">Film</h1>

        <div id="films">
            <!-- aggiunge film -->
        </div>

        <footer></footer>

        <script src="/Javascript/app.js"></script>
        <script src="/Javascript/Film/add.js"></script>
        <script src="/Javascript/Element/navbar.js"></script>
        <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
        <script>
            $(function(){
            $("nav").load("/Html/Elements/navbar.html"); 
            $("footer").load("/Html/Elements/footer.html");
            $("#mb-menu").load("/Html/Elements/mobile_menu.html"); 
            });
        </script>
    </body>
</html>
站点结构参考

站点目录结构参考

故障原因定位

共3处核心配置错误:

  1. 缓存资源列表路径错误,导致缓存写入中断
    • 所有Css开头的缓存路径都漏了根路径前缀/,和页面实际引用的/Css/xxx路径不匹配,请求直接返回404
    • 路径大小写不统一:/Html/Pages/amici_home.html使用小写amici目录,同目录下的tilde、kloe页面路径写为大写Amici目录,大小写敏感的服务器上这两个路径会返回404
    • 带空格的路径未做URL编码:/Javascript/Sito Bello/目录名包含空格,实际请求时空格会被编码为%20,和缓存列表中的原始字符串不匹配,请求返回404
    • cache.addAll是原子操作,只要列表中任意一个资源请求失败,整个缓存写入流程就会直接中断。
  2. Service Worker安装逻辑错误,提前激活拦截请求
    install事件回调中执行chache.addAll(assets)时没有返回对应Promise,导致evt.waitUntil()没有等待缓存全部写入完成就判定Service Worker安装成功,提前激活开始拦截网络请求。此时排在资源列表后面的页面类HTML要么还没写入缓存,要么写入中断返回残缺响应,浏览器收到无效响应直接报ERR_FAILED。
  3. fetch拦截逻辑缺少兜底,activate事件未做初始化处理
    • 现有fetch逻辑没有异常捕获,当缓存匹配失败、网络请求也出错时,会直接抛出异常,没有降级返回可用缓存
    • 没有针对导航类HTML请求做适配,URL参数、大小写差异都会导致缓存匹配失败
    • activate事件没有调用self.clients.claim(),Service Worker激活后无法立即接管已打开的页面,新旧缓存混用会进一步加剧加载异常;同时没有旧缓存清理逻辑,修改资源后用户端不会更新缓存。
修复方案
  1. 统一修正缓存资源列表的路径,所有路径统一加根前缀/,对齐实际目录大小写,带空格的路径把空格替换为%20,或者直接修改文件夹名去掉空格避免编码问题
  2. install事件中返回cache.addAll的Promise,确保所有资源缓存完成后再激活Service Worker
  3. 完善fetch拦截逻辑,增加异常捕获,对导航类请求增加兜底规则
  4. activate事件增加旧缓存清理逻辑,调用clients.claim()立即接管页面

修复后的核心Service Worker代码参考:

// 升级缓存版本号,后续修改静态资源后递增版本号即可自动清理旧缓存
const staticCacheName = 'site-static-v2'
const assets = [
    '/',
    '/index.html',
    '/Html/Elements/footer.html',
    '/Html/Elements/mobile_menu.html',
    '/Html/Elements/navbar.html',
    '/Html/Pages/film.html',
    '/Html/Pages/anime.html',
    '/Html/Pages/sitobello.html',
    '/Html/Pages/song.html',
    '/Html/Pages/amici_home.html',
    // 统一目录大小写,与实际服务器路径对齐
    '/Html/Pages/amici/tilde.html',
    '/Html/Pages/amici/kloe.html',

    // 补全所有Css路径的根前缀/
    '/Css/Index/style.css',
    '/Css/Sito%20Bello/background.css',
    '/Css/Sito%20Bello/section.css',
    '/Css/Sito%20Bello/settings.css',
    '/Css/Song/background.css',
    '/Css/Song/elementi.css',
    '/Css/Film/background.css',
    '/Css/Film/elementi.css',
    '/Css/Anime/background.css',
    '/Css/Anime/elementi.css',
    '/Css/Element/footer.css',
    '/Css/Element/mobile_menu.css',
    '/Css/Element/navbar.css',
    '/Css/Element/scrollbar.css',
    '/Css/Amici/Home/background.css',
    '/Css/Amici/Home/elementi.css',
    '/Css/Amici/Kloe/background.css',
    '/Css/Amici/Tilde/background.css',

    '/Images/Logo.png',
    '/Images/Index/background.jpg',

    '/Javascript/Element/navbar.js',
    '/Javascript/Film/add.js',
    // 空格替换为%20,建议直接修改文件夹名去掉空格
    '/Javascript/Sito%20Bello/add.js',
    '/Javascript/Sito%20Bello/settings.js',

    '/manifest.webmanifest',
    '/Javascript/app.js',
]

// 安装Service Worker
self.addEventListener('install', evt => {
    // 等待所有缓存写入完成再结束安装流程
    evt.waitUntil(
        caches.open(staticCacheName).then(cache => {
            console.log('caching shell assets')
            // 必须return addAll的promise
            return cache.addAll(assets)
        })
    )
    // 安装完成后立即跳过等待,激活新版本
    self.skipWaiting()
})

// 激活Service Worker
self.addEventListener('activate', evt => {
    evt.waitUntil(
        // 清理旧版本缓存
        caches.keys().then(keys => {
            return Promise.all(keys
                .filter(key => key !== staticCacheName)
                .map(key => caches.delete(key))
            )
        })
    )
    // 立即接管所有已打开的客户端页面
    self.clients.claim()
})

// 拦截fetch请求
self.addEventListener('fetch', evt => {
    // 只处理同域GET请求,跨域CDN资源直接走网络
    if (evt.request.method !== 'GET' || !evt.request.url.startsWith(self.location.origin)) {
        return
    }

    evt.respondWith(
        caches.match(evt.request, {
            // 忽略URL查询参数匹配,避免带参数的请求匹配不到缓存
            ignoreSearch: true,
            // 忽略Vary头匹配
            ignoreVary: true
        }).then(cacheRes => {
            // 缓存命中直接返回,未命中走网络请求,请求成功后写入缓存
            return cacheRes || fetch(evt.request).then(fetchRes => {
                // 克隆响应副本写入缓存,因为响应是流只能读取一次
                const resClone = fetchRes.clone()
                caches.open(staticCacheName).then(cache => {
                    cache.put(evt.request, resClone)
                })
                return fetchRes
            })
        }).catch(() => {
            // 异常兜底:如果是导航HTML请求,离线时返回首页缓存
            if (evt.request.mode === 'navigate') {
                return caches.match('/index.html')
            }
        })
    )
})

修复后需要在浏览器DevTools的Application面板中卸载旧的Service Worker,清除旧缓存后重新访问站点,即可正常加载所有缓存页面,支持整站离线访问。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 13:48:13