基于Node.js与MongoDB的Flutter应用本地数据存储与同步方案咨询
免费实现Flutter本地存储与Node.js/MongoDB服务器同步方案
一、本地存储选型(全免费)
- Hive:轻量级NoSQL本地数据库,适配结构化/半结构化数据存储,读写速度快,无需SQL基础,集成成本低,完全开源免费。适合创业项目快速迭代,能直接存储从服务器拉取的JSON格式数据。
- sqflite(SQLite):基于SQLite的Flutter插件,适合复杂关系型数据存储,支持事务、查询优化,功能强大且完全免费。如果你的业务数据存在复杂关联,这个选项更适配,学习成本略高但可控。
- SharedPreferences:仅适合存储键值对类型的小数据(比如同步时间戳、用户偏好设置),官方原生支持,免费且集成简单,但不适合存储大量业务数据。
二、数据同步逻辑(自研免费方案)
基于你的Node.js + MongoDB服务器,自行实现同步逻辑,无需依赖付费第三方服务:
- 增量同步(时间戳/版本号驱动)
- 服务器端给MongoDB的每个数据文档添加
updatedAt(更新时间)和version(版本号)字段。 - 客户端首次同步拉取全量数据,之后每次同步时,带上本地记录的最后同步时间戳或最大版本号,服务器返回该时间/版本之后新增、修改的数据。
- 客户端拿到数据后,更新本地存储,并同步更新本地的同步标记(时间戳/版本号)。
- 服务器端给MongoDB的每个数据文档添加
- 离线操作缓存
- 客户端离线时,将所有新增、修改、删除操作记录到本地操作队列(用Hive或sqflite存储),每条操作记录包含操作类型(增/删/改)、数据内容、操作时间。
- 联网后,客户端依次将队列中的操作发送到服务器,服务器执行操作后返回结果,客户端根据结果更新本地存储并移除队列中的对应操作。
- 冲突处理
- 当客户端和服务器同时修改同一条数据时,通过
version字段判断:客户端提交修改时带上本地数据的版本号,服务器检查该版本号是否与数据库中的一致。 - 如果版本号不一致,返回冲突提示,客户端可实现简单处理逻辑(比如提示用户选择保留本地修改还是服务器版本,或自动合并可兼容字段)。
- 当客户端和服务器同时修改同一条数据时,通过
三、核心代码示例
服务器端(Node.js + MongoDB)
// 处理增量同步请求 app.get('/sync', async (req, res) => { const lastSyncTime = req.query.lastSyncTime; const data = await db.collection('yourCollection').find({ updatedAt: { $gt: new Date(lastSyncTime) } }).toArray(); res.json({ data: data, latestSyncTime: new Date().toISOString() }); }); // 处理客户端提交的离线操作 app.post('/submit-offline-ops', async (req, res) => { const ops = req.body.ops; for (const op of ops) { switch(op.type) { case 'create': await db.collection('yourCollection').insertOne(op.data); break; case 'update': await db.collection('yourCollection').updateOne( { _id: op.data._id, version: op.data.version }, { $set: { ...op.data, version: op.data.version + 1, updatedAt: new Date() } } ); break; case 'delete': await db.collection('yourCollection').deleteOne({ _id: op.data._id }); break; } } res.json({ success: true }); });
Flutter客户端(Hive示例)
// 初始化Hive await Hive.initFlutter(); await Hive.openBox('dataBox'); await Hive.openBox('syncQueue'); // 增量同步逻辑 Future<void> syncData() async { final lastSyncTime = Hive.box('dataBox').get('lastSyncTime', defaultValue: DateTime(2000).toIso8601String()); final response = await http.get(Uri.parse('http://your-server/sync?lastSyncTime=$lastSyncTime')); if (response.statusCode == 200) { final data = jsonDecode(response.body)['data']; final latestSyncTime = jsonDecode(response.body)['latestSyncTime']; final box = Hive.box('dataBox'); for (var item in data) { box.put(item['_id'], item); } box.put('lastSyncTime', latestSyncTime); // 处理离线队列 await submitOfflineOps(); } } // 提交离线操作队列 Future<void> submitOfflineOps() async { final queue = Hive.box('syncQueue'); final ops = queue.values.toList(); if (ops.isNotEmpty) { final response = await http.post( Uri.parse('http://your-server/submit-offline-ops'), body: jsonEncode({'ops': ops}) ); if (response.statusCode == 200) { queue.clear(); } } }
内容的提问来源于stack exchange,提问作者UITHCM
相关产品推荐
相关产品推荐

