无数据库时Node.js主进程与Express路由共享数据的架构设计
无数据库场景下的Node.js设备数据管理方案
核心思路:封装独立的状态管理模块
把设备数据的读写、持久化逻辑全部集中到一个独立模块,让主进程、Express路由都通过这个模块操作数据,替代直接传递对象引用的方式,实现解耦和统一管控。
1. 实现数据状态模块(deviceStore.js)
这个模块是唯一的数据入口,负责初始化、读写、持久化所有设备数据:
const fs = require('fs').promises; const path = require('path'); // 内存中的设备数据(仅模块内部可直接修改) let deviceData = []; const STORAGE_FILE = path.join(__dirname, 'devices-backup.json'); // 从外部API加载初始数据,失败则尝试读本地备份 async function initFromAPI(apiUrl) { try { const res = await fetch(apiUrl); deviceData = await res.json(); await saveToDisk(); // 初始化后立即存盘 } catch (apiErr) { console.error('API拉取失败:', apiErr); // 降级加载本地备份 try { const savedStr = await fs.readFile(STORAGE_FILE, 'utf8'); deviceData = JSON.parse(savedStr); } catch (diskErr) { console.error('无本地备份可用:', diskErr); } } } // 获取设备数据(返回副本,避免外部直接篡改内存数据) function getDevices() { return JSON.parse(JSON.stringify(deviceData)); } // 修改设备数据:通过传入修改函数,在模块内部执行更新 function updateDevices(handleUpdate) { // 基于当前数据生成新数组,保证操作的原子性 deviceData = handleUpdate([...deviceData]); } // 将内存数据写入磁盘 async function saveToDisk() { try { await fs.writeFile(STORAGE_FILE, JSON.stringify(deviceData, null, 2)); } catch (err) { console.error('存盘失败:', err); } } // 启动定时存盘任务(默认30秒一次) function startAutoSave(intervalMs = 30000) { setInterval(saveToDisk, intervalMs); } module.exports = { initFromAPI, getDevices, updateDevices, startAutoSave, saveToDisk };
2. 主进程启动流程(index.js)
主文件只负责初始化数据、启动定时任务、启动服务器,不直接操作数据:
const { initFromAPI, startAutoSave } = require('./deviceStore'); const startExpress = require('./server'); async function bootstrap() { // 1. 加载初始设备数据 await initFromAPI('https://your-external-api/devices'); // 2. 启动自动存盘 startAutoSave(); // 3. 启动Express服务器 await startExpress(); } bootstrap();
3. Express服务器与路由集成
server.js:只负责服务器初始化,不处理数据逻辑
const express = require('express'); const deviceRoutes = require('./routes/devices'); const app = express(); app.use(express.json()); // 挂载路由,路由直接调用状态模块 app.use('/api', deviceRoutes); async function startServer() { return new Promise(resolve => { const server = app.listen(3000, () => { console.log('服务器运行在3000端口'); resolve(server); }); }); } module.exports = startServer;
routes/devices.js:通过状态模块处理请求
const express = require('express'); const { getDevices, updateDevices, saveToDisk } = require('../deviceStore'); const router = express.Router(); // GET 获取设备列表 router.get('/devices', (req, res) => { res.json(getDevices()); }); // POST 更新指定设备 router.post('/devices/:id', (req, res) => { const targetId = req.params.id; const updates = req.body; updateDevices(currentDevices => { return currentDevices.map(device => { if (device.id === targetId) { return { ...device, ...updates }; } return device; }); }); // 可选:修改后立即存盘(如果需要强一致性) saveToDisk().catch(err => console.error('更新后存盘失败:', err)); res.json({ msg: '设备已更新' }); }); // POST 新增设备 router.post('/devices', (req, res) => { const newDevice = req.body; updateDevices(currentDevices => [...currentDevices, newDevice]); res.status(201).json(newDevice); }); module.exports = router;
方案优势
- 解耦清晰:数据逻辑完全独立,主进程、路由只做调用,后续改存储方式(比如加数据库)只需要修改
deviceStore.js - 数据安全:通过返回副本、内部执行修改,避免外部直接篡改内存数据,防止意外副作用
- 一致性保障:定时存盘+可选即时存盘,保证内存数据和磁盘备份同步,进程重启后能恢复最近状态
- 扩展性强:后续加数据校验、操作日志、缓存逻辑,都可以在状态模块里扩展,不影响其他代码
内容的提问来源于stack exchange,提问作者jcornfishe
相关产品推荐
相关产品推荐

