如何基于Firestore实现支持离线编辑的多端数据同步?
离线优先多端加密数据同步方案(规避系统时间篡改问题)
核心思路是放弃客户端时间戳,改用服务器权威版本号+本地操作队列的模式,彻底摆脱系统时间依赖,同时保障离线编辑能力和数据一致性。
一、本地存储扩展设计
在localStorage中除了加密的data,新增以下字段:
localVersion:本地维护的自增整数,记录当前本地数据的操作版本(每次离线编辑+1)syncVersion:记录上次成功同步到服务器的版本号(初始为0)offlineOps:数组,存储离线状态下的所有操作记录,每条记录包含opType(编辑/删除等)、opContent(加密后的变更内容片段)、localOpVersion(对应本地的localVersion)
二、服务器端数据结构
服务器端为每个用户存储:
encryptedData:加密后的完整数据(和客户端data一致)serverVersion:服务器维护的自增整数(权威版本号,初始为0,每次合法更新自动+1)opHistory(可选):存储用户的历史操作日志(加密状态),用于冲突合并
三、同步核心流程
1. 离线编辑时
每次用户编辑数据:
- 生成一条加密的操作记录,追加到
offlineOps数组 - 更新本地
localVersion(+1) - 直接更新本地加密的
data,确保离线体验流畅
2. 在线同步时
客户端优先发起同步请求,流程如下:
第一步:拉取服务器最新版本
向服务器请求当前用户的serverVersion和对应版本的encryptedData
- 如果
serverVersion > syncVersion:说明其他设备有更新,先将本地data替换为服务器的最新加密数据,再把offlineOps中的操作按顺序重放应用到新数据上,生成合并后的加密数据 - 如果
serverVersion == syncVersion:直接使用本地当前的data(包含离线操作的结果)
第二步:推送更新到服务器
向服务器提交合并后的加密数据,同时带上本地的syncVersion:
- 服务器校验:如果客户端提交的
syncVersion等于当前serverVersion,则接受更新,将encryptedData替换为提交内容,serverVersion+1,返回最新的serverVersion给客户端 - 如果客户端提交的
syncVersion小于当前serverVersion:说明同步过程中又有其他设备完成了更新,拒绝本次推送,让客户端重新执行第一步拉取最新数据后再尝试
第三步:同步完成后
客户端更新syncVersion为服务器返回的最新版本,清空offlineOps数组
四、冲突处理方案
1. 严格版本校验(简单直接)
通过服务器版本号的强校验,确保只有基于最新服务器版本的更新才能被接受。如果客户端提交的版本号过期,强制客户端先拉取最新数据合并后再推送,避免旧数据覆盖新数据。
2. 细粒度操作合并(友好体验)
如果需要避免强制覆盖,可在服务器存储用户的加密操作日志:
- 客户端同步时,拉取自
syncVersion之后的所有服务器操作日志 - 将本地
offlineOps和服务器日志按操作发生的先后顺序(由版本号推导,而非时间戳)重放合并 - 若出现冲突(比如两段操作修改了同一文本位置),弹出提示让用户手动选择保留哪部分内容,再将合并结果推送给服务器
五、加密安全保障
所有在本地和服务器之间传输、存储的数据(包括操作日志、完整数据)始终保持加密状态,服务器仅作为存储和版本号维护的载体,无法解密用户数据,确保隐私安全。
内容的提问来源于stack exchange,提问作者Wor Chan
相关产品推荐
相关产品推荐

