如何在Workbox插件中缓存额外资源并遵守过期配置
问题描述
我希望编写一个Workbox插件,拦截特定API请求,通过逻辑确定其他可缓存的URL,然后将其添加到运行时缓存中。现有代码如下:
export class PreCachePlugin implements WorkboxPlugin { fetchDidSucceed: WorkboxPlugin["fetchDidSucceed"] = async ({ response, }) => { if (response.ok) { const clonedResponse = await response.clone(); const json = await clonedResponse.json(); const urls: string[] = getUrlsToCache(json); // 省略此逻辑 await Promise.all(urls.map(async url => { const response = await fetch(url); // TODO:如何获取这些URL并存入下方配置的缓存,同时遵守expiration.maxEntries设置? })); } } }
使用workbox-webpack-plugin的GenerateSW配置如下:
new GenerateSW({ include: [/\.js$/, /\.json$/, /\.html$/], runtimeCaching: [ { urlPattern: ({ url }) => url.toString().endsWith("/foo"), handler: "StaleWhileRevalidate", options: { cacheName: "Foo", expiration: { maxEntries: 100 }, plugins: [ new PreCachePlugin(), ], }, }, ], swDest: "./sw.js", })
请问如何将新获取的URL存入配置的运行时缓存,同时遵守expiration.maxEntries设置?
解决方案
你可以借助Workbox提供的CacheExpiration(来自workbox-expiration)和CacheableResponsePlugin(来自workbox-cacheable-response)工具类,手动处理缓存逻辑并对齐runtimeCaching中的过期规则。具体修改如下:
import { CacheExpiration } from 'workbox-expiration'; import { CacheableResponsePlugin } from 'workbox-cacheable-response'; export class PreCachePlugin implements WorkboxPlugin { fetchDidSucceed: WorkboxPlugin["fetchDidSucceed"] = async ({ response, cacheName, event, }) => { // 确保cacheName存在且原始响应正常 if (response.ok && cacheName) { const clonedResponse = await response.clone(); const json = await clonedResponse.json(); const urls: string[] = getUrlsToCache(json); // 初始化缓存过期管理实例,同步runtimeCaching中的expiration配置 const cacheExpiration = new CacheExpiration(cacheName, { maxEntries: 100, // 和runtimeCaching配置保持一致 // 如果有其他过期规则(如maxAgeSeconds),请同步添加 }); // 配置可缓存的响应规则,对齐Workbox默认逻辑 const cacheableResponse = new CacheableResponsePlugin({ statuses: [200, 206], // 仅缓存状态码为200/206的响应 }); await Promise.all(urls.map(async (url) => { const request = new Request(url); // 先检查缓存是否已有该条目,避免重复请求 const cachedResponse = await caches.match(request, { cacheName }); if (!cachedResponse) { const newResponse = await fetch(request); // 验证响应是否符合缓存条件 if (cacheableResponse.cacheWillUpdate?.({ response: newResponse, request })) { // 将响应存入指定缓存 await caches.open(cacheName).then(cache => cache.put(request, newResponse.clone())); // 更新缓存条目时间戳,用于过期判断 await cacheExpiration.updateTimestamp(request.url); // 清理超出maxEntries限制的旧缓存 await cacheExpiration.expireEntries(); } } })); } // 必须返回原始响应,否则原API请求会失败 return response; } }
关键说明
- 缓存规则对齐:通过
CacheExpiration手动管理缓存过期,确保和runtimeCaching中expiration.maxEntries的限制逻辑完全一致。 - 响应合法性校验:使用
CacheableResponsePlugin过滤可缓存的响应,避免存入无效或错误的响应内容。 - 避免重复请求:先检查缓存中是否已存在目标URL的条目,减少不必要的网络请求。
- 保持原请求正常:插件最后必须返回原始API响应,否则拦截的API请求会因无返回值而失败。
内容的提问来源于stack exchange,提问作者Muhammad Rehan Saeed
相关产品推荐
相关产品推荐

