第 5 章:云开发架构详解
"Serverless 不是没有服务器,而是你不需要管理服务器。"
本章我们将深入后端代码 (server/ 目录),看看如何用 Node.js 编写优雅的云函数。
5.1 什么是 Serverless?
简单理解:你写一个函数 main(),把代码上传给腾讯云。当有请求来时,腾讯云分配计算资源运行它;运行结束,资源释放。
- FaaS (Function as a Service): 云函数。
- BaaS (Backend as a Service): 云数据库、云存储、云鉴权。
5.2 云函数设计模式
观察 server/activity/index.js,你会发现一种通用的模式:单体函数路由模式 (Monolithic Function Routing)。
我们没有为"创建活动"、"删除活动"分别创建几百个云函数,而是按业务领域聚合。
代码结构剖析
javascript
// server/activity/index.js
// 1. 引入依赖 & 初始化
const cloudbase = require('@cloudbase/node-sdk')
const app = cloudbase.init({ env: process.env.TCB_ENV_ID })
const models = app.models
// 2. 辅助函数 (Utils)
const checkAdminPermission = (role) => { ... }
// 3. 入口函数 (Main Entry)
exports.main = async (event, context) => {
const { action, data, token } = event
// 3.1 全局鉴权 (JWT Middleware)
const verification = verifyJWT(token)
if (!verification.valid) return { code: 401, ... }
// 3.2 路由分发 (Dispatcher)
switch (action) {
case 'createActivity':
return await createActivity(data, context) // 调用业务逻辑
case 'getActivityList':
return await getActivityList(data, context)
// ...
}
}
// 4. 业务逻辑函数 (Controllers)
const createActivity = async (data) => {
// 参数校验
// 权限检查
// 数据库操作
return { code: 0, message: '成功' }
}
这种模式的优点:
- 冷启动优化: 减少了云函数的数量,复用容器热身。
- 代码复用: 共享数据库连接、工具函数和鉴权逻辑。
5.3 云数据库操作封装
我们使用了 @cloudbase/node-sdk 提供的 models 对象(或者直接使用 db 引用)。
常用操作范式
-
查询 (List)
javascriptconst { data: result } = await models.activities.list({ filter: { where: { _id: 'act_123', deleted: false // 记得过滤软删除 }, offset: 0, limit: 20 } }) -
创建 (Create)
javascriptawait models.activities.create({ data: { title: '...', createdAt: dayjs().valueOf() // 记得打时间戳 } }) -
原子更新 (Atomic Update) 在投票场景下,为了防止并发冲突,我们使用数据库原子操作符(如
$inc,虽然本项目目前的 update 逻辑较简单,但这是高并发场景的最佳实践)。
5.4 云存储与 CDN 加速
文件存储 (models.storage 或前端 uniCloud.uploadFile) 主要用于:
- 活动封面 : 图片上传后获得
cloud://...格式的 FileID。 - 支付凭证: 用户上传的截图。
CDN 加速 : 云存储的文件默认走 CDN。在小程序端展示图片时,可以直接使用 cloud:// 路径,微信底层会自动转换为 HTTPS CDN 链接,加载速度飞快。
5.5 权限模型设计
我们在代码层面实现了严格的 RBAC (Role-Based Access Control)。
1. Token 里的秘密
JWT Token 的 payload 包含:
json
{
"userId": "u_123",
"role": "admin" // 核心权限字段
}
2. 装饰器式的权限检查
在敏感操作(如 deleteActivity)开头,有一行"守门员"代码:
javascript
const permissionError = checkAdminPermission(userRole)
if (permissionError) return permissionError
如果 userRole 不是 admin 或 super_admin,直接返回 403 错误。
3. 数据所有权检查
对于普通用户操作(如删除自己的报名),我们需要检查 userId 是否匹配:
javascript
if (record.userId !== currentUserId) {
return { code: 403, message: '只能操作自己的数据' }
}
本章小结: 通过云函数的"路由模式"和"鉴权中间件",我们构建了一个安全、高效的后端。不需要配置 Nginx,不需要写 Dockerfile,一切都在代码里。下一章,我们将详细讲解用户认证系统------那个 JWT Token 是怎么生成和流转的。