浏览器 Service Worker 缓存策略新增限制怎样排查
我在排查 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()。

把“新增限制”拆成响应类型和存储配额
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 时无条件清空所有缓存,否则会把更新责任变成每个请求的额外开销。

// 激活新版本时只保留明确允许的缓存名,便于回滚和清理
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 中途接管可能造成资源版本混用。对有强缓存依赖的应用,宁可让用户下一次导航自然切换,也要先把版本兼容关系设计清楚。
一张排查清单:先复现,再决定是否改策略
| 现象 | 优先检查 | 常见处理 |
|---|---|---|
| 注册成功但页面不走 worker | HTTPS、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
Redis JSON.SET 新参数怎样影响写入兼容性
- 上一篇
- Redis JSON.SET 新参数怎样影响写入兼容性
- 下一篇
- GitHub Changelog 怎样订阅团队真正关心的更新
-
- 科技周边 · 业界新闻 | 1小时前 | github · 业界新闻 · 团队协作 · rss 团队协作 GitHub Changelog GitHub Notifications 开发者平台
- GitHub Changelog 怎样订阅团队真正关心的更新
- 306浏览 收藏
-
- 科技周边 · 业界新闻 | 1小时前 |
- Redis JSON.SET 新参数怎样影响写入兼容性
- 321浏览 收藏
-
- 科技周边 · 业界新闻 | 1小时前 | MySQL · 查询优化 · explain index 生成列 MySQL 8.4 generated column JSON_UNQUOTE SHOW WARNINGS
- MySQL 8.4 生成列索引优化怎样判断是否命中
- 127浏览 收藏
-
- 科技周边 · 业界新闻 | 1小时前 |
- Python 3.14 标准库新增压缩能力怎样使用
- 374浏览 收藏
-
- 科技周边 · 业界新闻 | 1小时前 |
- Java SE 26 Class-File API 怎样改写方法字节码
- 218浏览 收藏
-
- 科技周边 · 业界新闻 | 1小时前 | CI/CD · gitHub actions · workflow GitHub Actions 工作流兼容性 actions.lock runner
- GitHub Actions 新变化怎样检查工作流兼容性
- 400浏览 收藏
-
- 科技周边 · 业界新闻 | 1小时前 |
- GitHub Copilot VS Code 九月更新怎样影响日常编码
- 399浏览 收藏
-
- 科技周边 · 业界新闻 | 1小时前 | openai · OpenAI 语音助手 自定义声音 gpt-live-1 prompt-to-voice Live API
- OpenAI gpt-live-1 prompt-to-voice 怎样接入
- 161浏览 收藏
-
- 科技周边 · 业界新闻 | 1小时前 | 模型迁移 工具调用 Responses API OpenAI GPT-6.1 Sol
- OpenAI GPT-6.1 Sol 发布后工具调用怎样迁移
- 219浏览 收藏
-
- 科技周边 · 业界新闻 | 1小时前 |
- GitHub App 安装令牌变长后怎样排查集成兼容性
- 316浏览 收藏
-
- 科技周边 · 业界新闻 | 1小时前 | Responses API 缓存命中 Prompt Caching OpenAI API 12小时缓存
- OpenAI API 12 小时 prompt caching 更新怎样影响调用设计
- 461浏览 收藏
-
- 科技周边 · 业界新闻 | 23小时前 |
- 云原生 systemd 崩溃重启 怎样处理
- 329浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 606次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 645次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 675次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 640次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 461次使用
-
- Adobe Express怎么安装到电脑?网页版、PWA入口与更新检查
- 2026-08-15 324浏览
-
- AI 应用怎样区分用户取消和模型完成
- 2026-10-14 354浏览
-
- AI 编程代理进入工程主流程:从官方动态看团队落地的三个信号
- 2026-06-13 214浏览
-
- 机器人 PR 运行 CI/CD 需要审批:GitHub Actions 新变化给团队的安全提醒
- 2026-06-13 473浏览
-
- GitHub Agentic Workflows 公测:AI 代理开始进入 Actions 自动化流水线
- 2026-06-13 354浏览

