Node.js + SQLite 轻量后端:用户系统与数据同步方案
用 Express + sql.js 搭建零配置后端的实践,涵盖认证、同步和管理后台。
一、为什么选 sql.js
传统 SQLite 需要编译原生模块(better-sqlite3、sqlite3),在不同环境部署时经常遇到编译问题。sql.js 是 SQLite 的纯 JavaScript 实现(通过 Emscripten 编译),零配置、零编译:
const initSqlJs = require('sql.js')
const SQL = await initSqlJs()
const db = new SQL.Database() // 内存数据库
// 导出为文件
const data = db.export()
const buffer = Buffer.from(data)
fs.writeFileSync('liuyao.db', buffer)
缺点是数据全部在内存中,需要定期 flush 到磁盘。我们的策略是每 5 分钟自动保存 + 每日备份 + 写操作后立即保存。
二、JWT 认证
用户认证采用 JWT + bcrypt 方案:
// 注册
const passwordHash = bcrypt.hashSync(password, 10)
db.run('INSERT INTO users (phone, password_hash) VALUES (?, ?)',
[phone, passwordHash])
const token = jwt.sign({ id, phone, role }, JWT_SECRET, { expiresIn: '30d' })
// 登录验证
const validPassword = bcrypt.compareSync(password, user.password_hash)
if (!validPassword) return res.status(401).json({ error: '手机号或密码错误' })
中间件在每个需要认证的请求上检查 token:
function authMiddleware(req, res, next) {
const token = req.headers.authorization?.substring(7)
if (tokenBlacklist.has(token))
return res.status(401).json({ error: '令牌已失效' })
const decoded = jwt.verify(token, JWT_SECRET)
req.user = decoded
next()
}
三、本地 + 云端双存储
前端采用双存储策略:未登录时用 localStorage,登录后自动同步到云端:
// 登录后自动迁移本地数据到云端
async function migrateLocalToCloud() {
const cloudKeys = new Set(cloudHistory.map(h => `${h.hexName}_${h.dateText}`))
const localOnly = localHistory.filter(h => !cloudKeys.has(...))
for (const item of localOnly) {
await api.post('/history', { hexData: item.hex, sectionsData: item.sections })
}
await loadFromCloud() // 重新加载
}
收藏和笔记通过 PUT /history/:id 同步到云端的 is_favorite 和 note 字段,不再使用独立的 localStorage。
四、数据持久化
sql.js 的数据只在内存中,必须手动保存。我们的策略:
- 写操作后立即保存 — 每次 INSERT/UPDATE/DELETE 后调用
saveDatabase() - 定时保存 — 每 5 分钟自动 flush 到磁盘
- 每日备份 — 凌晨 3 点复制 DB 文件到 backups/ 目录,保留 7 天
- 优雅退出 — SIGINT 信号时先保存再关闭
// 每日自动备份
function autoBackup() {
saveDatabase()
const date = new Date().toISOString().slice(0, 10)
fs.copyFileSync('db/liuyao.db', `db/backups/liuyao-${date}.db`)
// 清理 7 天前的备份
files.filter(f => statSync(f).mtimeMs < cutoff).forEach(f => unlinkSync(f))
}
五、管理后台
管理后台是一个独立的 Vue 3 SPA,构建后由 Express 静态托管:
// server.js
app.use('/admin', express.static(path.join(__dirname, 'admin/dist')))
app.get('/admin/*', (req, res) => {
res.sendFile(path.join(__dirname, 'admin/dist/index.html'))
})
功能包括:数据概览、用户管理(封禁/重置密码)、卦例数据、邀请码管理、AI 统计、系统管理(备份/导出/清理)。
六、安全措施
- 注册限流:每 IP 每小时 3 次
- 登录限流:每 IP+手机号每分钟 5 次
- 全局限流:每 IP 每分钟 100 次请求
- 密码加密:bcrypt 10 轮盐值
- Token 吊销:内存黑名单,退出登录时加入
- 封禁检查:每个认证请求都查一次用户状态
对于一个轻量级应用,这套方案足够了。如果将来需要扩展到多实例部署,需要把 SQLite 换成 PostgreSQL,JWT 黑名单换成 Redis。