service worker 本身不能直接保存表单数据,但可协同 indexeddb 和 cache api 实现离线提交:拦截 form submit → 序列化存入 indexeddb pendingsubmissions 仓库 → 网络恢复时通过 background sync 或 postmessage 触发 fetch 重发 → 前后端配合 uuid 与幂等接口防重复 → 页面加载时查询状态并提示用户。

Service Worker 本身不能直接保存用户填写的表单数据,但它可以配合 IndexedDB 和 Cache API,在离线时拦截提交请求、暂存数据,并在网络恢复后自动重发。核心思路是:拦截表单提交 → 序列化数据 → 存入 IndexedDB → 监听网络状态 → 自动重试提交。
拦截表单提交并缓存到 IndexedDB
不要在页面 JS 中直接调用 fetch 提交,而是统一通过自定义事件或拦截 form 的 submit 事件,将数据转为结构化对象后存入 IndexedDB:
- 在页面中监听
submit,阻止默认行为,序列化表单字段(如用new FormData(form)或手动提取) - 调用封装好的存储函数,把 { url, method, body, timestamp } 写入 IndexedDB 的
pendingSubmissions对象仓库 - 建议为每条记录生成唯一 ID(如
crypto.randomUUID()),方便后续追踪和去重
Service Worker 中监听网络恢复并重发
Service Worker 无法主动监听“网络恢复”,但可通过 fetch 事件 + 定期轮询或 sync 事件实现可靠重试:
- 注册
sync事件(需先调用registration.sync.register('submit-form')),在 Service Worker 中监听并读取 IndexedDB 中待提交的数据 - 对每条记录执行
fetch(url, { method, body, ... }),成功后从 DB 中删除;失败则可设置重试次数上限(如最多 3 次) - 若不支持
sync(如 Safari),可用fetch事件配合页面发送的自定义消息(postMessage)触发重试逻辑
处理重复提交与服务端幂等性
离线缓存 + 自动重发可能引发重复提交,必须从前端和后端协同解决:
- 前端每次提交前生成唯一请求 ID(如 UUID),随表单数据一并保存和发送
- 后端接口根据该 ID 做幂等判断(例如 Redis 缓存 ID 10 分钟,已存在则直接返回成功)
- Service Worker 重发失败时,可在 IndexedDB 中标记状态(如
status: 'failed'),供页面加载时提示用户手动重试
页面加载时同步未完成状态
用户刷新页面后,需让 UI 反映离线提交的进度:
- 页面初始化时打开 IndexedDB,查询
pendingSubmissions中 status 为'pending'或'failed'的记录 - 显示“正在重试…”、“提交已暂存,网络恢复后自动发送”等提示,并提供手动重试按钮
- 点击重试时,向 Service Worker 发送
postMessage({ type: 'retry', id: xxx })触发单条重发
不复杂但容易忽略:IndexedDB 需提前在页面或 Service Worker 中初始化 schema;fetch 请求头(如 Content-Type: application/json)要在存储前固化;所有异步操作(openDB、put、get)都要正确 await 或链式处理。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











