Cache Storage:离线 PWA 背后的请求/响应存储
发布于
一句话: Cache Storage 是面向 Request/Response 对、按源限定的可编程存储——service
worker 用它在离线时提供资源与 API 响应。与浏览器自动管理的 HTTP 缓存不同,由你显式决定它
保存什么。
Cache Storage 对比 HTTP 缓存与 IndexedDB
Section titled “Cache Storage 对比 HTTP 缓存与 IndexedDB”- HTTP 缓存由浏览器自动管理,且与 Cache Storage 相互独立;Cache API 不遵循 HTTP 缓存 响应头。你无法直接读写 HTTP 缓存。
- Cache Storage 是一个你直接掌控的存储:你显式地
put、match、delete整个Response对象,以Request为键。它让 service worker 的fetch处理器能够在无网络时应答请求。 - IndexedDB 存储结构化记录与 blob,而非 HTTP 响应。应用数据(草稿、排队的变更)用 IndexedDB;应用外壳与已取资源用 Cache Storage。
CacheStorage—— 在窗口、Worker 与 service worker 中以caches暴露。它是命名Cache对象的注册表:caches.open(name)、caches.has(name)、caches.delete(name)、caches.keys(),以及在所有缓存中跨库查找的便捷方法caches.match()。Cache—— 单个命名的请求→响应条目存储。关键方法:cache.put(request, response)—— 存入你已有的一对。cache.add(request)/cache.addAll(requests)—— 一步取回并存储。cache.match(request)/cache.matchAll()—— 查找已存储的响应。cache.delete(request)—— 移除一个条目。
Cache 存储 Response 对象。由于响应体只能被读取一次,当你还想把响应返回给页面时,请存储
一个克隆(response.clone())。
它在哪里运行、用来做什么
Section titled “它在哪里运行、用来做什么”caches 在窗口、Web Worker 中可用,并且——关键在于——在 service worker 中可用,这正是让
service worker 的 fetch 事件能在网络不可用时从缓存应答的原因。在 install 期间预存应用
外壳,然后在 fetch 中按你选定的策略从缓存提供,并回退到(或从)网络更新。
const CACHE = 'shell-v3';const ASSETS = ['/', '/app.css', '/app.js', '/offline.html'];
self.addEventListener('install', (event) => { event.waitUntil(caches.open(CACHE).then((cache) => cache.addAll(ASSETS)));});
self.addEventListener('activate', (event) => { // 删除旧缓存,避免新部署永远提供陈旧文件。 event.waitUntil( caches.keys().then((names) => Promise.all(names.filter((n) => n !== CACHE).map((n) => caches.delete(n))) ) );});
self.addEventListener('fetch', (event) => { event.respondWith( caches.match(event.request).then((hit) => hit || fetch(event.request)) );});版本管理与清理
Section titled “版本管理与清理”在正常使用下,Cache Storage 不会自行移除你的条目——你放入的内容会一直存在,直到你删除它。 这使得一套刻意的版本管理方案不可或缺:
- 给缓存名加上版本(
shell-v3)。资源变化时提升名称。 - 在
activate中删除被取代的缓存(如上),让上一版本的文件被回收,而非不断累积。 - 谨慎对待不透明响应。 跨源
no-cors请求会产生状态为0的不透明响应,它只能用put存储;仅在必须时才缓存它们。
配额与持久化
Section titled “配额与持久化”Cache Storage 的数据计入由 Storage API 管理的源存储用量,与 IndexedDB 等其他 web 存储一起
计算。当达到配额上限时,浏览器可能逐出某个源的存储,因此把缓存的资源当作可丢弃的,并
随时准备重新获取。在数据必须经受逐出之处,用 navigator.storage.persist() 申请持久存储。
(完整的配额与逐出模型见存储持久化参考。)
浏览器与生态支持
Section titled “浏览器与生态支持”Cache Storage API(CacheStorage 与 Cache)在当前主流浏览器上获得支持,并且可从 service
worker 访问,使其成为 PWA 离线资源的基线存储。
- 请求/响应类资源用 Cache Storage;结构化应用数据用 IndexedDB。
- 若还要把响应返回给页面,缓存前先
clone()。 - 给缓存名加版本,资源变化时提升名称。
- 在 service worker 的
activate事件中删除旧缓存。 - 把缓存视为可丢弃;为重新获取做好设计,数据必须经受逐出时调用
persist()。 - 谨慎缓存不透明的跨源响应——你无法检查它们。