Cache API 是浏览器提供的一种存储机制,专门用于缓存
Request/Response对象对。它与 Service Worker 紧密配合,是实现渐进式 Web 应用(PWA)离线可用、性能优化的核心工具。以下从多个维度对 Cache API 进行系统分析。
一、 概述
Cache API 允许开发者精确控制网络资源的缓存策略。与传统的 HTTP 缓存不同,Cache API 是程序化的,开发者可以决定哪些资源被缓存、何时缓存、何时更新,并能在离线状态下直接返回缓存的响应。
注:Cache API 在 window 和 worker 上下文中均可直接使用,无需依赖 Service Worker,但与 Service Worker 的 fetch 事件结合是其主要应用场景。
- 接口来源:
caches全局对象(属于Window或WorkerGlobalScope)。 - 存储模型:以 缓存仓库(CacheStorage) 为顶层,内部包含多个命名 缓存对象(Cache),每个缓存对象存储多个键值对,其中键是
Request对象,值是Response对象。 - 生命周期:由开发者显式管理(添加、删除、匹配),数据可持久化,但浏览器可能在存储压力下自动清除(尤其是未使用
persist标记时)。
二、 核心特性
1. 存储内容
- 键:
Request对象(通常使用 URL 字符串作为标识,但也可包含请求方法、头等信息)。 - 值:
Response对象(支持所有 HTTP 响应特性,如状态码、头信息、body)。 - 可以存储跨域资源(CORS 响应需设置
crossorigin属性)。 - ⚠️ 注意:若跨域请求使用 mode: 'no-cors',得到的响应为 不透明响应(opaque response),其状态码固定为 0,body 不可读,且缓存后无法判断资源是否已更新。应避免将不透明响应用于关键业务逻辑。
2. API 接口
| 方法 | 说明 |
|---|---|
caches.open(name) | 打开(或创建)指定名称的缓存对象,返回 Promise<Cache>。 |
cache.put(request, response) | 将请求-响应对存入缓存。 |
cache.add(request) / addAll(requests) | 自动 fetch 请求并将结果存入缓存。 |
cache.match(request, options) | 匹配给定请求的缓存响应。 |
cache.delete(request, options) | 删除匹配的缓存条目。 |
caches.keys() | 获取所有缓存仓库名称。 |
caches.delete(name) | 删除整个缓存仓库。 |
3. 作用域与权限
- 可用环境:Service Worker、Window、Worker、SharedWorker。
- 同源限制:缓存仓库与源(origin)绑定,不同源的页面无法访问彼此的缓存(但 Service Worker 可拦截跨域请求并缓存跨域响应)。
- 安全上下文:仅在 HTTPS(或 localhost)环境下可用,确保数据在传输和存储过程中的安全性。
4. 容量与持久性
- 配额:与 IndexedDB 共享存储空间,通常可达到几百 MB 甚至更多,具体取决于浏览器和磁盘可用空间。
- 持久性:默认情况下,缓存数据可能被浏览器在存储压力下自动清除(如用户清理站点数据,或浏览器自动驱逐旧数据)。可以通过 Storage Manager API 请求持久化存储(
navigator.storage.persist()),减少被清除的概率。 - 开发者可通过 navigator.storage.estimate() 查看当前源下所有存储机制(含 Cache API)的 usage 和 quota,辅助制定清理策略。
三、 与 Service Worker 的协作
Cache API 最常见的使用场景是作为 Service Worker 的缓存引擎。Service Worker 在安装、激活、fetch 事件中操作 Cache API,实现离线优先或网络优先的策略。
典型流程
- 安装阶段:预缓存关键静态资源(HTML、CSS、JS、图标)。
self.addEventListener("install", (event) => { event.waitUntil( caches .open("v1") .then((cache) => cache.addAll(["/", "/styles.css", "/app.js"])), ); }); - 激活阶段:清理旧缓存。
- 请求阶段:根据策略决定返回缓存还是网络响应。
self.addEventListener("fetch", (event) => { event.respondWith( caches.match(event.request).then((response) => { return response || fetch(event.request); }), ); });
缓存策略示例
- Cache Only:完全离线。
- Network Only:仅网络(不缓存)。
- Cache First (Stale-While-Revalidate):优先返回缓存,后台更新。
- Network First:优先网络,失败时使用缓存。
- Cache Then Network:先返回缓存,再请求网络更新 UI。
四、 主要使用场景
| 场景 | 说明 |
|---|---|
| 离线 Web 应用 (PWA) | 核心存储机制,确保用户在没有网络时仍能访问基本功能和内容。 |
| 静态资源缓存 | 缓存 HTML、CSS、JS、图片等,实现秒开和减少服务器负载。 |
| API 响应缓存 | 缓存接口数据,提升二次加载速度,支持弱网环境。 |
| 后备内容(Fallback) | 当网络请求失败时,返回缓存的默认页面或占位图。 |
| 版本化管理 | 通过缓存名称(如 v1、v2)实现原子化更新,避免新旧资源混用。 |
五、 安全与限制
1. 安全上下文
- Cache API 只在 HTTPS(或 localhost)中可用,确保缓存数据不会被中间人篡改。
2. 跨域资源缓存
- 可以缓存跨域资源(如 CDN 上的字体、图片),但需要这些资源支持 CORS 且请求时携带
mode: 'cors'。 - 缓存的跨域响应可能受 CORS 策略限制(例如无法访问响应头),但仍可作为静态资源使用。
3. 敏感数据
- 缓存的数据(包括响应正文)以明文形式存储在磁盘上,因此不应缓存密码、Token 等高度敏感信息。
- 如果必须缓存,应确保内容本身已加密,且密钥不在客户端暴露。
4. 清除策略
- 用户可以通过浏览器设置清除所有站点数据,包括 Cache API 存储。
- 浏览器在磁盘空间不足时可能自动清除缓存,尤其是未请求持久化的缓存。
- Chrome/Edge:采用 LRU 策略,优先清理最久未被访问的缓存条目。
- Safari:受 ITP 影响,若站点在 7 天内无用户交互,所有脚本可写存储(含 Cache API)将被清除。
- 开发者可通过
caches.delete()主动管理,避免无限增长。
5. 隐私追踪
- Cache API 与 IndexedDB 一样,可能被用于跨站追踪。主流浏览器(如 Safari 的 ITP)会对持久存储施加限制,例如自动清除 7 天未访问站点的缓存数据。
六、 与其他存储 API 的对比
| 特性 | Cache API | IndexedDB | Web Storage | HTTP Cache |
|---|---|---|---|---|
| 存储内容 | Request/Response 对象 | 任意结构化数据 | 键值对(字符串) | 原始响应(由浏览器管理) |
| API 类型 | 异步(Promise) | 异步(Promise/回调) | 同步 | 自动 |
| 粒度控制 | 精确到每个请求 | 精确到每条记录 | 精确到每个键 | 基于 HTTP 头(Cache-Control) |
| 离线可用 | 是(配合 Service Worker) | 是 | 是 | 仅当资源已缓存且未过期 |
| 更新策略 | 完全程序控制 | 程序控制 | 程序控制 | 由服务器头控制 |
| 跨标签共享 | 同源共享 | 同源共享 | localStorage: 共享;sessionStorage: 不共享 | 共享(基于域名) |
| 容量 | 较大(几百 MB) | 较大(几百 MB+) | 较小(5-10 MB) | 由浏览器决定 |
| 适用场景 | 资源缓存、离线应用 | 大量结构化数据、离线数据 | 简单配置、临时状态 | 自动性能优化 |
七、 性能考量
1. 异步非阻塞
所有 Cache API 操作都是异步的,不会阻塞 UI 线程,适合在 Service Worker 或后台任务中大量使用。
2. 匹配效率
cache.match()会按 URL 精确匹配,也支持忽略查询字符串、忽略方法等选项。- 对于大量缓存,匹配操作性能良好,但应避免在每次 fetch 事件中都进行复杂的匹配逻辑。
3. 存储开销
- 缓存重复的响应会浪费空间,应合理规划缓存键和清理策略。
- 响应 body 会被完整存储,大文件(如视频)可能快速消耗配额。
4. 持久化存储请求
- 使用
navigator.storage.persist()可降低数据被自动清除的风险,但用户仍可手动清除。
5. Navigation Preload 加速
- 当用户发起导航请求时,Service Worker 启动需要时间。启用 Navigation Preload 后,浏览器会在 SW 启动同时并行发送网络请求。
- 在 fetch 事件中可通过 event.preloadResponse 获取该预加载响应,与缓存匹配结果进行对比,选择最快或最新的响应返回。
八、 最佳实践
1. 版本化缓存
- 使用带版本号的缓存名称(如
myapp-static-v2),在 Service Worker 激活时删除旧版本。 - 避免将不同版本的资源混在同一个缓存中,防止不一致。
2. 合理选择缓存策略
- 静态资源:预缓存 + 缓存优先(stale-while-revalidate)。
- API 数据:网络优先 + 后台更新,或使用 Cache then Network 模式。
- 离线回退:对导航请求预缓存离线页面。
3. 处理跨域资源
- 确保跨域资源响应包含
Access-Control-Allow-Origin且请求时设置mode: 'cors'。 - 对于不支持 CORS 的资源(如某些 CDN 字体),可以使用
no-cors模式缓存,但响应内容不可读(opaque response),且不保证可靠更新。
4. 错误处理与回退
- 在
fetch事件中始终处理网络异常,返回缓存的备用响应。 - 记录缓存操作失败的情况,便于调试。
5. 清理未使用的缓存
- 在 Service Worker 激活事件中,对比当前版本号,删除其他所有缓存仓库。
- 定期清理过期数据(如超过 30 天未使用的 API 缓存)。
6. 避免缓存敏感数据
- 不在缓存中存储用户凭证、支付信息等敏感内容。如需离线使用,应结合加密方案。
7. 使用 Workbox 抽象复杂性
- Google 官方出品的 Workbox 库提供了生产级的缓存策略、预缓存清单生成、过期清理等功能。
- 推荐在复杂 PWA 中使用 Workbox,避免重复造轮子,减少缓存管理漏洞。
九、 未来趋势
- 持久化存储的标准化:已落地,navigator.storage.persist() 广泛支持。
- 缓存分区(Partitioned Cache):已实施,Firefox 最早,Chrome 自 2023 年起默认启用。
- 更强的离线能力:随着 Web 应用日益复杂,Cache API 与 Background Sync、Periodic Sync 等 API 结合,实现更智能的后台更新。
- 新增趋势:Web Bundles API 与 Subresource Loading with Web Bundles 可能改变资源分发的缓存模式,Cache API 需配合处理 bundle 内资源。
十、 总结
Cache API 是现代 Web 开发中实现高性能、高可用性(特别是离线体验)的关键基础设施。它与 Service Worker 紧密结合,赋予开发者对网络请求响应的精细控制能力。
- 优势:编程式缓存、异步非阻塞、支持跨域资源、容量大、与 Service Worker 深度集成。
- 局限:仅在安全上下文可用、数据可能被自动清除、不适合存储敏感信息、API 相对底层(可借助 Workbox 简化)。
- 适用场景:PWA 离线应用、静态资源缓存、API 数据缓存、渐进式性能优化。
合理使用 Cache API,结合良好的缓存策略和版本管理,可以大幅提升 Web 应用的可靠性、响应速度和用户体验。随着浏览器存储机制的演进,Cache API 将持续扮演“应用层缓存”的核心角色。