service worker可通过fetch拦截、流式读取、indexeddb分块存储与动态组装实现大文件可控分块缓存。具体为:拦截请求→用response.body.getreader()分块读取→存入indexeddb(key为文件名+序号)→缓存元数据至cache api→命中时按序读块构造readablestream响应→配合降级策略保障兼容性。

Service Worker 本身不直接支持“分块缓存”(如 HTTP 分块传输或文件切片),但它可以通过组合 fetch 事件拦截、Response 流式读取、Cache API 分段写入和 IndexedDB 存储,实现对大文件(如视频、安装包)的可控分块缓存与按需组装。核心不是让 Cache API 拆块,而是绕过其单次写入限制,用更底层方式管理缓存单元。
用流式响应 + 分块写入 IndexedDB
Cache API 要求整个 Response 对象一次性存入,无法直接缓存超大响应体。可行路径是:在 fetch 事件中拦截请求 → 获取 ReadableStream → 按固定 chunkSize(如 1MB)读取 Uint8Array → 将每个块存入 IndexedDB(用文件名+块序号作 key)。
- 使用
response.body.getReader()获取流读取器,循环调用read() - 每读取一块,用
IDBObjectStore.put()存为{ fileId: 'video.mp4', index: 0, data: chunk } - 记录总块数和文件元信息(size、mime、hash)到单独 objectStore,便于后续拼接校验
缓存命中时动态组装响应流
当再次请求同一文件时,Service Worker 不走网络,而是从 IndexedDB 逐块读取并构造可流式响应的 ReadableStream:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 查出该文件所有块,按
index升序排列 - 创建自定义
ReadableStream,在pull(controller)中依次读取块并controller.enqueue(chunk) - 返回
new Response(stream, { headers: { 'Content-Type': mime } }) - 浏览器端能正常播放/下载,就像服务端分块传输一样
配合 Cache API 做元数据缓存
虽然大文件本体存在 IndexedDB,但可把轻量元数据(如重定向地址、ETag、块索引列表、校验摘要)存进 Cache API,提升查询效率:
- 缓存一个虚拟的
/__meta/video.mp4请求,响应体为 JSON:{ totalChunks: 127, etag: "abc123", chunks: [0,1,...126] } - 这样只需一次
caches.match()就能知道文件是否完整可用,避免全量查 IndexedDB - 更新时先更新 Cache 中的元数据,再异步写入新块,保证一致性
注意边界与降级策略
流式读写和 IndexedDB 在低内存设备或后台页面可能失败,需有 fallback:
- 设置 chunk size ≤ 512KB,避免单块读写超时或内存溢出
- 捕获
DOMException: QuotaExceededError,自动切换为仅缓存前 N 块(如封面帧、关键帧) - 对不支持
ReadableStream的旧浏览器(如 Safari 15.4-),回退到传统整文件缓存或跳过缓存 - 添加
cache.addAll()预加载小资源(图标、CSS),确保基础 UI 可离线访问
不复杂但容易忽略:分块缓存的价值不在“节省空间”,而在“可控加载”——比如视频拖拽时只取对应区间块,或安装包按需解压某模块。真正落地时,重点是设计好块索引协议和错误恢复逻辑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










