主题切换
服务端与云开发实践
预计阅读 35 分钟
版本信息
最后更新:2026-07-09 · 适用基础库:≥ 3.9.0(最低兼容 ≥ 2.30.0)· Node.js ≥ 18
前端工程师转型独立开发者时,往往对服务端开发感到陌生。本章讲解小游戏中最常见的服务端需求:登录鉴权、米大师支付回调、排行榜、开放数据域服务端方案,并对比微信云开发与自建服务器的适用场景。
云开发 vs 自建服务器
| 维度 | 微信云开发 | 自建服务器 |
|---|---|---|
| 运维成本 | 低,免服务器运维 | 高,需部署、监控、扩容 |
| 成本曲线 | 按调用量计费,初期便宜 | 固定成本,规模大了更划算 |
| 灵活性 | 受限于云函数能力 | 完全可控 |
| 数据库 | 云数据库,有容量限制 | 自选 MySQL/MongoDB/Redis |
| 适合阶段 | 原型 / 小型项目 | 商业化 / 中重度项目 |
| 网络延迟 | 微信生态内较优 | 取决于机房和 CDN |
建议:原型期用云开发快速验证;商业化后迁移到自建服务器以获得更低边际成本和更高可控性。
登录鉴权
核心流程
- 前端调用
wx.login()获取code。 - 前端将
code发送给服务端。 - 服务端调用
jscode2session换取openId和session_key。 - 服务端生成自定义登录态(如 JWT)返回前端。
Node.js 示例
typescript
// server/auth.ts
import crypto from 'crypto'
import axios from 'axios'
const APP_ID = process.env.WX_APP_ID!
const APP_SECRET = process.env.WX_APP_SECRET!
export async function login(code: string) {
const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${APP_ID}&secret=${APP_SECRET}&js_code=${code}&grant_type=authorization_code`
const { data } = await axios.get(url)
if (data.errcode) {
throw new Error(`微信登录失败: ${data.errmsg}`)
}
const { openid, session_key, unionid } = data
// 生成自定义登录态
const token = generateToken(openid)
// 将 session_key 安全存储,用于后续敏感数据解密
await saveSessionKey(openid, session_key)
return { openid, unionid, token }
}
function generateToken(openid: string): string {
return crypto
.createHmac('sha256', process.env.JWT_SECRET!)
.update(openid + Date.now())
.digest('hex')
}session_key 必须服务端保管
session_key 是解密用户敏感数据(如手机号、运动数据)的密钥,绝对不能下发到客户端。应加密存储在服务端数据库或 Redis 中。
米大师支付回调与订单校验
为什么必须服务端校验
客户端的 wx.requestMidasPayment.success 回调可以被伪造或篡改。生产环境必须通过服务端确认订单真实状态。
服务端校验流程
前端支付成功 → 将 { orderId, code } 发送给服务端
↓
服务端用 code 换取 openId
↓
服务端调用米大师「查询订单」接口
↓
确认金额、状态、签名无误
↓
发放道具并持久化到数据库简化的 Node.js 校验示例
typescript
// server/payment.ts
import crypto from 'crypto'
interface MidasOrder {
orderId: string
openId: string
offerId: string
buyQuantity: number
status: 'SUCCESS' | 'PENDING' | 'FAIL'
}
export async function verifyOrder(orderId: string, openId: string): Promise<MidasOrder> {
// 实际应调用微信米大师查询订单接口
// 这里仅展示校验签名和状态的逻辑框架
const order = await queryMidasOrder(orderId, openId)
const sign = generateMidasSign(order)
if (sign !== order.signature) {
throw new Error('订单签名无效')
}
if (order.status !== 'SUCCESS') {
throw new Error(`订单状态异常: ${order.status}`)
}
return order
}
function generateMidasSign(order: Record<string, any>): string {
const secret = process.env.MIDAS_SECRET!
const sorted = Object.keys(order)
.filter((k) => k !== 'signature')
.sort()
.map((k) => `${k}=${order[k]}`)
.join('&')
return crypto.createHmac('sha256', secret).update(sorted).digest('hex')
}排行榜服务端方案
全局排行榜
使用 Redis 有序集合(Sorted Set)是最高效的方式:
typescript
// server/ranking.ts
import Redis from 'ioredis'
const redis = new Redis(process.env.REDIS_URL)
export async function updateScore(openId: string, score: number) {
// ZADD 会自动去重并保留最高分
const current = await redis.zscore('ranking:weekly', openId)
if (!current || score > Number(current)) {
await redis.zadd('ranking:weekly', score, openId)
}
}
export async function getTopPlayers(topN = 100) {
const list = await redis.zrevrange('ranking:weekly', 0, topN - 1, 'WITHSCORES')
const result = []
for (let i = 0; i < list.length; i += 2) {
result.push({ openId: list[i], score: Number(list[i + 1]), rank: i / 2 + 1 })
}
return result
}好友排行榜
好友排行榜需要用户授权访问好友关系,数据存储在微信云端。服务端无法直接获取好友列表,因此通常采用:
- 前端通过
wx.getFriendCloudStorage获取好友数据。 - 将数据交给开放数据域渲染(参见 开放数据域)。
- 服务端仅负责存储和同步玩家自己的最高分。
云开发示例
typescript
// 云函数 login/index.js
const cloud = require('wx-server-sdk')
cloud.init()
exports.main = async (event) => {
const { OPENID } = cloud.getWXContext()
const db = cloud.database()
const user = await db.collection('users').doc(OPENID).get()
if (!user.data) {
await db.collection('users').add({
data: {
_id: OPENID,
createdAt: db.serverDate(),
bestScore: 0,
},
})
}
return { openId: OPENID }
}📝 课后练习
练习 1:设计排行榜接口
题目: 设计一个获取周排行榜 Top 100 的 HTTP 接口,要求:
- 需要鉴权(token 校验)。
- 返回排名、openId 掩码、分数。
- 接口有缓存,避免每次请求都打 Redis。
参考答案要点:
- 使用
zrevrange获取 Top 100。 - openId 脱敏处理,如
user_*****1234。 - 使用 Redis 缓存结果 30 秒。
- token 校验失败返回 401。
本章小结
- 登录鉴权:前端只传 code,服务端用 jscode2session 换取 openId 和 session_key。
- 支付校验:必须服务端调用米大师接口确认订单,客户端 success 不可信。
- 排行榜:全局榜用 Redis Sorted Set,好友榜依赖微信开放数据域。
- 云开发适合原型和小型项目,商业化后建议迁移到自建服务器。
- session_key 和支付密钥必须服务端安全存储,绝不泄露到客户端。