同步失败主因是WebView本地存储被清空或Cookie/SameSite策略导致认证失败,需检查localStorage/indexedDB状态、手动注入Cookie、校验响应头ETag及indexedDB连接状态。

同步失败时先看 localStorage 和 indexedDB 是否被清空
很多“同步出错”其实根本没走到网络层,而是本地存储在 WebView 重启或 APP 升级后被意外清除。iOS WKWebView 默认不持久化 localStorage,Android 某些定制 ROM 也会限制 indexedDB 生命周期。检查方式很简单:在调试页面中执行 localStorage.getItem('sync_token') 或 indexedDB.databases(),返回 null 或空数组就说明本地状态已丢失。
- 修复方案:强制在 APP 启动时调用
window.resolveLocalFileSystemURL(Cordova)或使用capacitor-storage(Capacitor)接管持久化,避开 WebView 自带存储的不确定性 - 别依赖
localStorage存关键同步元数据,比如最后同步时间戳、版本号,这些必须进原生层或加密写入文件系统 - 如果用的是 PWA 封装成 APP,确认
manifest.json中"storage": "persistent"已声明(仅部分 Android 支持)
fetch 请求 401 或 403 但网页端正常?检查 Cookie 与 SameSite 策略
WebView 默认不携带 Cookie(尤其 iOS),或因 SameSite=Lax 导致服务端拒绝认证凭据。现象是网页打开一切正常,APP 内请求直接 401,且 Network 面板看不到 Cookie 被发送。
- Android:在
WebView.getSettings().setAllowUniversalAccessFromFileURLs(true)之后,还需调用CookieManager.getInstance().setCookie(url, cookieString)手动注入 - iOS:WKWebView 不共享 Safari Cookie,必须用
WKHTTPCookieStore显式 set,且需在webView.configuration.websiteDataStore初始化后操作 - 服务端若校验
Origin头,注意 APP 内 WebView 的Origin是file://或自定义 schema,需白名单放行
增量同步卡在某条记录?查 ETag 和 Last-Modified 响应头是否缺失
APP 端常通过比对服务端返回的 ETag 或 Last-Modified 判断数据是否变更,但很多后端 API 忘记设置这些头,导致前端永远认为“有更新”,反复拉取同一份数据并冲突。
- 用抓包工具(如 Charles)对比网页端和 APP 请求的完整响应头,重点看是否缺失
ETag、Last-Modified、Cache-Control - 前端同步逻辑里,如果服务端没返回
ETag,别 fallback 到时间戳比对——时间精度不同(秒 vs 毫秒)、时区不一致极易误判 - 更稳妥的做法:服务端在响应体中显式返回
"version": "20240520142200"字段,APP 用该字段做乐观锁比对
离线编辑后同步失败,错误信息含 DOMException: The database has not been opened
这是 indexedDB 在后台进程被回收后的典型报错。APP 切到后台再切回,或长时间未操作,Chrome/WebKit 可能终止数据库连接,但 JS 代码仍试图复用旧的 IDBDatabase 实例。
立即学习“前端免费学习笔记(深入)”;
- 所有
indexedDB操作前加守卫:检查db.readyState === 'open',否则重新open() - 不要把
db实例挂全局变量,每次操作都走indexedDB.open()+onupgradeneeded流程,哪怕只是读取 - 离线队列建议用轻量方案替代:改用
localStorage存 JSON 数组(每条含 action/type/payload/timestamp),同步成功后再删,避免 DB 锁死风险











