cache api只能在service worker线程中使用,页面主线程调用caches.open()会因安全限制抛出securityerror或返回undefined;必须通过https(或localhost)注册service worker,并在install事件中用event.waituntil()包裹caches.open()与cache.addall()操作。

Cache API 不能在 HTML 页面脚本里直接创建或管理缓存——它只能在 Service Worker 线程中运行,页面主线程调用 caches.open() 会抛出 SecurityError 或返回 undefined。
为什么 caches.open() 在页面里调用失败
浏览器明确禁止在主线程(即普通 <script></script> 标签或模块脚本)中访问 caches 全局对象。这不是兼容性问题,而是安全限制:Cache API 设计上必须与 Service Worker 绑定,确保缓存操作发生在受控、隔离的后台线程中。
常见错误现象:
- 控制台报错:
SecurityError: caches is not available in this context - 或静默失败:
caches为undefined,调用caches.open()报TypeError: Cannot read property 'open' of undefined
正确前提只有两个:
- Service Worker 已注册成功:
navigator.serviceWorker.register('/sw.js')(路径需同源,且协议为 HTTPS 或localhost) -
sw.js文件已部署,并能在浏览器中直接访问(例如打开https://yoursite.com/sw.js应返回 JS 内容,状态码 200)
如何在 Service Worker 中创建并预填充缓存
缓存创建本身很简单,但关键在于时机和可靠性。最常用的是在 install 事件中调用 caches.open() 并写入资源,但必须用 event.waitUntil() 包裹整个异步链,否则缓存操作会被中断。
示例(sw.js):
self.addEventListener('install', event => {
const cacheName = 'static-v1';
const filesToCache = [
'/',
'/index.html',
'/app.js',
'/style.css',
'/logo.png'
];
event.waitUntil(
caches.open(cacheName)
.then(cache => cache.addAll(filesToCache))
.catch(err => console.error('Preload failed:', err))
);
});
注意点:
-
cache.addAll()是原子操作:列表中任意一项 404、跨域无 CORS、或非 GET 请求,整个调用都会 reject,缓存不会写入任何内容 - 路径必须是根相对路径(如
'/app.js'),不能用'./app.js'或'app.js' - HTML 文件本身要显式列出;它内部引用的资源(如
<script src="app.js"></script>)不会被自动递归抓取
fetch 事件中怎么安全读写缓存
缓存真正起作用是在 fetch 事件里拦截请求、匹配已有缓存、或回退到网络。这里最容易踩坑的是请求体消费和匹配精度。
典型安全写法:
self.addEventListener('fetch', event => {
const { request } = event;
// 只对 GET 请求做缓存处理(POST/PUT 不该进 Cache Storage)
if (request.method !== 'GET') return;
// 按 destination 分流,避免污染
if (request.destination === 'document') {
event.respondWith(
caches.match(request)
.then(cached => cached || fetch(request))
);
} else if (['script', 'style', 'image', 'font'].includes(request.destination)) {
event.respondWith(
caches.match(request)
.then(cached => cached || fetch(request).then(res => {
// 只缓存成功响应(200–299)
if (res.status >= 200 && res.status {
cache.put(request, res.clone());
return res;
});
}
return res;
}))
);
}
});
关键细节:
-
request.clone()必须在cache.put()前调用,否则原始Responsebody 已被读取,再 clone 就是空流 -
cache.match()默认严格匹配 URL 字符串(含 query 参数顺序),/api/data?id=1&name=test≠/api/data?name=test&id=1 - 若服务端对带参数的静态资源做版本控制(如
/main.css?v=2.1),建议在缓存前标准化 URL,或改用ignoreSearch: true选项
怎么验证缓存是否真的生效
别信 Network 面板里的 from cache ——那只是 HTTP 缓存,和 Cache API 完全无关。真实写入的缓存只在 DevTools 的 Application → Cache Storage 里可见。
验证步骤:
- 打开 DevTools(
F12),切到Application标签页 → 左侧展开Cache Storage - 刷新页面,观察是否有你定义的缓存名(如
static-v1)出现 - 点开缓存名,看条目列表是否包含你预设的路径(
/index.html、/app.js等) - 点击某条目,在下方
Preview标签页确认能正常渲染或显示文本内容;同时检查Headers区域是否有Status: 200 OK
如果条目存在但 Preview 为空,大概率是缓存时存入了非 200 响应(比如 304、404)、或 Response body 已被提前消费、或跨域未配 CORS。
最后提醒:缓存名建议带版本号(如 static-v2),每次更新 Service Worker 时,在 activate 事件里用 caches.delete() 清理旧缓存——这步漏掉,旧缓存永远不会自动消失,只会越积越多。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











