做 PocketEgg(习惯养成小程序)的时候,我面临一个典型的独立开发者困境:既要写前端,又要写后端,还要管服务器、配数据库、搞 HTTPS 证书……一个人精力实在有限。
最后选择了微信「云开发」方案,整个后端部分几乎没有写传统意义上的"服务器代码",部署和运维成本接近于零。这篇文章聊聊这套方案的具体用法和踩过的坑。
1. 为什么选云开发,而不是自建后端
自建后端(比如 Node.js + Express + MySQL)的优势是灵活、可控,但代价是:
- 需要购买和维护服务器
- 需要处理 HTTPS 证书、域名备案
- 需要自己写鉴权、防刷、限流逻辑
- 数据库的备份、扩容都要自己操心
对于一个还没验证市场需求的小项目,这些成本前置投入太大。微信云开发把这些都封装好了——数据库、文件存储、云函数、定时任务、甚至 HTTPS 都是开箱即用的,而且和小程序的鉴权体系(openid)天然集成,不需要自己写登录注册。
2. 云数据库:用集合代替表
云开发的数据库是基于 MongoDB 的,概念上是"集合(Collection)"而不是"表",每条记录是一个 JSON 文档,不需要预先定义字段结构,这对快速迭代特别友好。
// 在小程序端直接读写数据库(受安全规则控制) const db = wx.cloud.database() // 新增一条打卡记录 await db.collection('checkins').add({ data: { habitId: 'habit_001', date: formatDate(new Date()), _openid: // 自动注入,无需手动传递 } })
3. 云函数:写业务逻辑的地方
有些逻辑不适合放在客户端执行(比如涉及多用户数据的统计、需要调用第三方API、需要服务端密钥的操作),这时候就用云函数。云函数本质上是部署在云端的 Node.js 函数,按调用次数计费。
const cloud = require('wx-server-sdk') cloud.init() exports.main = async (event, context) => { const { OPENID } = cloud.getWXContext() const db = cloud.database() // 统计该用户连续打卡天数(聚合查询,客户端无法直接做) const records = await db.collection('checkins') .where({ _openid: OPENID }) .orderBy('date', 'desc') .get() return { streak: calcStreak(records.data) } }
PocketEgg 里所有涉及"积分计算"、"排行榜统计"、"成就解锁判定"的逻辑,都放在云函数里,避免客户端被篡改数据。
4. 云存储与CDN
用户上传的头像、习惯图标这类文件,存在云存储里,自带 CDN 加速,不需要额外配置七牛云或阿里云OSS。上传逻辑也很简单:
const res = await wx.cloud.uploadFile({ cloudPath: `avatars/${openid}.png`, filePath: tempFilePath // 用户选择的图片临时路径 }) // res.fileID 即可直接用于 <image> 组件展示
5. 几个真实踩过的坑
- 数据库查询默认限制100条 —— 第一次做排行榜功能时只显示了100个用户,后来才发现需要用
skip分页或者云函数里调整limit - 云函数冷启动延迟 —— 长时间没有调用的云函数首次执行会有1-2秒延迟,对实时性要求高的场景需要注意
- 安全规则容易写错 —— 一次更新安全规则时不小心把"仅创建者可写"改成了"所有人可写",幸好测试环境发现及时
- 定时触发器的时区问题 —— 云函数的定时任务默认是UTC时间,做"每天0点重置"这类逻辑时要注意换算成北京时间
6. 成本与限制
云开发有免费额度(数据库读写次数、云函数调用次数、存储空间都有每日/每月免费量),PocketEgg 早期用户量不大的时候完全在免费额度内,超出之后按量计费,整体成本远低于自己租服务器。
需要注意的限制是:云开发深度绑定微信生态,如果未来要做多端(比如同时支持App、H5),数据层需要做额外的适配工作。但对于"只做微信小程序"的项目,这几乎是性价比最高的选择。