当前位置:首页 > 文章列表 > 科技周边 > 业界新闻 > 浏览器 Service Worker 缓存策略新增限制怎样排查

浏览器 Service Worker 缓存策略新增限制怎样排查

来源:17golang原创 2026-10-23 06:09:37 0浏览 收藏

我在排查 Service Worker 缓存问题时,最容易误判的一件事,是把“以前能缓存、现在不命中”直接归结为浏览器新增了限制。实际更常见的情况是:站点不再满足安全上下文,Service Worker 没有控制当前页面,跨源响应变成了 opaque,或者新旧缓存版本同时存在。先把这几层拆开,才能知道到底该改策略、改响应头,还是只清理旧缓存。

官方资料:https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API

遇到“缓存策略突然失效”,先确认安全上下文、controller、响应类型和 Cache Storage 配额,再看 match 规则与版本清理。不要先把所有请求改成 no-store,也不要用 ignoreSearch 掩盖错误的 URL 设计。

缓存策略突然不生效,先确认是哪一层在限制

Service Worker 和 Cache API 依赖安全上下文,生产环境通常是 HTTPS,本地开发的 http://localhost 由浏览器作为开发便利条件处理。即使脚本注册成功,也要确认当前页面已经被它控制;第一次打开页面时,注册、安装和接管可能还没有完成。

我会先在页面控制台看 navigator.serviceWorker.controller,再在 Application 面板检查注册的 scope、活动 worker 和 Cache Storage。若 controller 为空,优先处理作用域、页面刷新和激活状态,而不是修改 caches.match()。

安全上下文、Service Worker 控制权、Cache Storage、同源响应、opaque 响应和存储配额之间的原创静态关系说明图
图1:Service Worker 缓存限制的边界说明图,展示安全上下文、控制权、响应类型和存储配额之间的关系;这是原创说明图,不是浏览器截图。

把“新增限制”拆成响应类型和存储配额

cache.add()、cache.addAll() 和 cache.put() 并不是无条件接收任何响应。跨源请求在没有合适 CORS 配置时可能得到 opaque 响应,脚本无法读取其中的状态码和响应头;这会让“只缓存 2xx、只缓存指定 Content-Type”的判断失去依据。

更容易被忽略的是配额计算。Chrome DevTools 文档提示,opaque 响应在配额统计中可能按带填充的较大占用计算,单个响应的计费下限约为 7 MB;这个数字是浏览器实现说明,不应当当作所有浏览器都相同的通用规范。若缓存的是跨源字体、图片或接口结果,先在 Network 中确认响应类型,再查看 navigator.storage.estimate() 的使用量和上限。

// 只把明确成功、且能读取响应头的同源资源写入缓存
async function cacheSameOrigin(cache, request, response) {
  const sameOrigin = new URL(request.url).origin === self.location.origin;
  const contentType = response.headers.get("content-type") || "";
  if (!sameOrigin || response.type === "opaque" || !response.ok) {
    return false;
  }
  if (!contentType.includes("text/") && !contentType.includes("javascript")) {
    return false;
  }
  // 复制响应,避免缓存读取和页面返回争用同一个 body 流
  await cache.put(request, response.clone());
  return true;
}

这段判断适合需要可解释性的静态资源策略;如果业务确实要缓存跨源资源,就必须接受 opaque 的可观测性和配额边界,不能只因为 fetch() 没抛异常就认为它适合长期保存。

请求匹配不命中,先查 URL、方法和 Vary

Cache Storage 不是“只要 URL 看起来一样就一定命中”。Cache.match() 默认会考虑请求方法和响应的 Vary,查询参数也参与匹配。于是,/app.js?v=1 与 /app.js?v=2 可能是两个键;把 ignoreSearch: true 打开后虽然能命中旧资源,却可能把本应区分的版本或租户数据混在一起。

排查时建议把请求的 url、method、destination、cache 和响应的 status、type 记录在开发环境日志里。HTTP 4xx/5xx 响应不会自动变成网络异常,不能只在 catch 里处理;先检查 response.ok,再决定是否写入 Cache Storage。

// 只为 GET 请求提供缓存优先、网络回退的资源策略
self.addEventListener("fetch", (event) => {
  const request = event.request;
  if (request.method !== "GET") {
    return;
  }
  event.respondWith((async () => {
    // 默认保留查询参数和 Vary 语义,避免误合并不同版本资源
    const cached = await caches.match(request);
    if (cached) {
      return cached;
    }
    try {
      const network = await fetch(request);
      if (network.ok && network.type === "basic") {
        const cache = await caches.open("assets-v3");
        // 页面拿原响应,缓存拿副本;写缓存失败不应阻断本次网络响应
        event.waitUntil(cache.put(request, network.clone()).catch(() => undefined));
      }
      return network;
    } catch (error) {
      // 网络失败时返回已有离线资源;没有回退资源就交给浏览器报错
      return (await caches.match("/offline.html")) || Response.error();
    }
  })());
});

正确做法:把缓存策略写成可回滚的版本

如果确认问题来自策略变更,建议为缓存名加版本,例如 assets-v3,并在 activate 阶段删除不在允许列表中的旧缓存。不要在每次 fetch 时无条件清空所有缓存,否则会把更新责任变成每个请求的额外开销。

fetch 事件、Request、Cache.match、网络回退、Response.clone、Cache.put、CACHE_NAME 与 activate 清理之间的原创静态结构图
图2:可回滚缓存策略的结构说明图,展示请求匹配、网络回退、响应复制、写入与旧版本清理的关系;这是原创结构图,不代表一次真实运行。
// 激活新版本时只保留明确允许的缓存名,便于回滚和清理
const CACHE_ALLOW_LIST = ["assets-v3", "pages-v2"];

self.addEventListener("activate", (event) => {
  event.waitUntil((async () => {
    const cacheNames = await caches.keys();
    await Promise.all(cacheNames.map((name) => {
      if (!CACHE_ALLOW_LIST.includes(name)) {
        // 删除旧版本,避免旧资源和新策略长期并存
        return caches.delete(name);
      }
      return undefined;
    }));
    // 让新 worker 尽快接管已打开的页面;是否启用要结合应用更新风险评估
    await self.clients.claim();
  })());
});

更新时还要留意旧 worker 的 waiting 状态。强制 skipWaiting() 可以缩短等待,但如果旧页面已经加载了一部分旧资源,新 worker 中途接管可能造成资源版本混用。对有强缓存依赖的应用,宁可让用户下一次导航自然切换,也要先把版本兼容关系设计清楚。

一张排查清单:先复现,再决定是否改策略

现象优先检查常见处理
注册成功但页面不走 workerHTTPS、scope、controller、激活状态刷新或调整注册路径,确认控制范围
跨源资源写入后配额很快满response.type、资源数量、storage estimate减少 opaque 缓存或改用可读的 CORS 响应
缓存永远不命中查询参数、请求方法、Vary、缓存名固定 URL 规则,谨慎使用匹配选项
更新后仍返回旧内容waiting worker、旧缓存、激活清理版本化缓存并明确接管策略

这套顺序的价值在于,先判断“限制发生在哪一层”,再决定是修部署、修响应、修匹配还是修生命周期。若只看到一次 QuotaExceededError 就全面关闭缓存,通常会损失离线能力,却没有解决 opaque 响应或缓存版本管理的问题。

常见问题

浏览器是不是新增了一个统一的 Service Worker 缓存上限?

不能这样概括。Cache Storage 的可用空间和 opaque 响应的配额计费具有浏览器和实现差异;排查时应记录具体浏览器、响应类型、存储估算和错误,再讨论限制。

把 caches.match 的 ignoreSearch 设为 true 能解决版本缓存吗?

它只改变匹配时是否忽略查询串,可能掩盖版本键设计问题。只有当查询参数确实不影响资源内容时才考虑使用,否则应统一资源 URL 或采用明确的缓存名版本。

缓存写入失败要不要让页面请求也失败?

多数静态资源策略可以让页面先拿到网络响应,再用 event.waitUntil() 异步写缓存;但安装阶段的核心资源如果写入失败,可能应该让安装失败并在下一次更新时重试。两者要按资源重要性区分。

官方资料:https://developer.mozilla.org/en-US/docs/Web/API/Cache、https://developer.mozilla.org/en-US/docs/Web/API/Cache/match、https://developer.chrome.com/docs/devtools/progressive-web-apps

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Redis JSON.SET 新参数怎样影响写入兼容性Redis JSON.SET 新参数怎样影响写入兼容性
上一篇
Redis JSON.SET 新参数怎样影响写入兼容性
GitHub Changelog 怎样订阅团队真正关心的更新
下一篇
GitHub Changelog 怎样订阅团队真正关心的更新
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    606次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    645次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    675次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    640次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    461次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码