首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >云开发做会员小程序:完整前后端和微信支付从零到上线

云开发做会员小程序:完整前后端和微信支付从零到上线

原创
作者头像
gavin1024
发布于 2026-11-06 14:28:20
发布于 2026-11-06 14:28:20
1190
举报

摘要: 用云开发 CloudBase 做会员小程序,支付走云调用,不用处理证书和签名,回调也由云函数接收。整条链路四步:小程序下单、云函数生成订单、小程序调起支付、云函数接回调发货。 开通环境开始做会员小程序:云开发 CloudBase

先说清一件事:小程序接微信支付,技术上最费劲的从来不是写代码,而是证书管理、签名计算和回调服务器。云开发的云调用把这三件事全接走了——云函数里调一个 cloudPay.unifiedOrder 就能生成订单,回调直接指向另一个云函数,你不需要有公网服务器、不需要配 HTTPS 回调地址、不需要下载和保管商户证书。下面从数据建模到支付回调给完整实现,再把上线前必须核对的细节列出来。

一、先把会员小程序拆成四块

会员小程序听起来复杂,其实就四块,每块对应云开发的一项能力:

模块

要解决的问题

用什么实现

用户身份

知道当前是谁

微信登录 + 云函数里取 OPENID

会员数据

存等级、到期时间、权益

云数据库 users 集合

商品与订单

卖什么、卖了什么

云数据库 products / orders 集合

支付

收钱与发货

云调用 + 两个云函数

这四块的依赖顺序是固定的:身份 → 数据 → 订单 → 支付。不要跳着做,支付调不通的问题,有一半源头在前面三步没打牢(比如订单里没存 openid,回调时不知道给谁开会员)。

二、开工前的前置条件

云开发侧:已开通云开发环境,拿到环境 ID。正式收钱的项目建议用付费套餐,别用免费环境承载真实交易——额度一停业务就断。

微信侧(这部分卡的是资质,不是技术):

  • 小程序是正式注册账号,有真实 AppID,测试号不支持云开发也不能支付
  • 主体已申请微信支付商户号(在微信支付商户平台申请)
  • 小程序后台完成支付开通,并与商户号建立关联

资质审核的要求、可开通的支付类目、费率与结算周期,各主体类型不同,以微信支付官方规则为准。这块没过,代码写得再对也收不到钱,建议先去把资质办下来再动手写。

三、数据建模:三个集合怎么设计

先建集合再写代码,顺序反了后面要返工。

products(商品 / 会员套餐)

字段

说明

name

套餐名称,如「月度会员」

price

价格,单位:分(和支付接口保持一致,避免换算错误)

duration

会员时长,单位:天

desc

权益说明

status

上下架状态

权限设为所有用户可读、仅创建者可写。商品要让所有人看到,但不能让用户改价格。

users(用户与会员状态)

字段

说明

openid

用户唯一标识,从云函数取

level

会员等级

expireAt

会员到期时间

createTime

首次注册时间

权限设为仅创建者可读写。更关键的一条:会员等级和到期时间这两个字段,绝不能让前端直接写,必须由支付回调云函数写入。否则用户可以自己改成永久会员。

orders(订单)

字段

说明

outTradeNo

商户订单号,必须不重复

openid

下单用户

productId

购买的套餐

totalFee

金额,单位:分

status

订单状态:pending / paid / failed

createTime / payTime

下单与支付时间

权限设为仅创建者可读写,写入和状态流转都走云函数。

这里有个权限设计原则值得记住:凡是涉及钱和权益的写操作,一律收敛到云函数里做,前端只读不写。 前端能写的字段,就等于用户能改的字段。

四、支付链路:四步完整实现

云开发的云调用天然打通微信支付接口,无需关心证书、签名,基于微信私有协议和私有链路,并支持用云函数接收支付回调。下面四步是完整闭环。

第 1 步:小程序端调用云函数下单

用户在商品页点「购买」,前端不直接碰支付,而是先让云函数生成订单:

代码语言:js
复制
// 小程序端:pages/product/product.js
wx.cloud.callFunction({
  name: "makeOrder",
  data: {
    productId: this.data.productId,  // 买哪个套餐
  },
});

第 2 步:云函数生成订单,返回支付参数

云函数 makeOrder 做三件事:查商品真实价格、写订单记录、调统一下单接口。价格必须从数据库查,不能用前端传过来的值,否则会被改价。

代码语言:js
复制
// 云函数 makeOrder/index.js
const cloud = require("wx-server-sdk");
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV });
const db = cloud.database();

exports.main = async (event, context) => {
  // 1. 取当前用户身份,不信任前端传入
  const { OPENID } = cloud.getWXContext();

  // 2. 从数据库查商品真实价格,避免前端改价
  const product = await db.collection("products").doc(event.productId).get();
  const totalFee = product.data.price;   // 单位:分

  // 3. 生成不重复的商户订单号
  const outTradeNo = `${Date.now()}${Math.floor(Math.random() * 10000)}`;

  // 4. 写入订单记录,状态为待支付
  await db.collection("orders").add({
    data: {
      outTradeNo,
      openid: OPENID,
      productId: event.productId,
      totalFee,
      status: "pending",
      createTime: db.serverDate(),
    },
  });

  // 5. 调用统一下单,无需证书和签名
  const res = await cloud.cloudPay.unifiedOrder({
    body: product.data.name,          // 商品描述
    outTradeNo,                       // 商户订单号
    spbillCreateIp: "127.0.0.1",
    subMchId: "你的商户号",
    totalFee,                         // 金额,单位:分
    envId: "你的环境ID",
    functionName: "payCallback",      // 支付结果回调的云函数名
  });

  return res;
};

几个参数容易写错,单独说明:totalFee 单位是分,1 元要传 100;outTradeNo 必须不重复,重复会下单失败,用时间戳加随机数是最省事的做法;functionName 填的是接收回调的云函数名,不是 URL。

第 3 步:小程序端调起微信支付

拿到云函数返回的支付参数后,用 wx.requestPayment 调起支付界面:

代码语言:js
复制
// 小程序端
wx.cloud.callFunction({
  name: "makeOrder",
  data: { productId: this.data.productId },
  success: (res) => {
    const payment = res.result.payment;   // 云函数返回的支付参数
    wx.requestPayment({
      ...payment,
      success(res) {
        wx.showToast({ title: "支付成功" });
        // 注意:这里只是用户侧支付成功,开通会员要等回调
      },
      fail(res) {
        wx.showToast({ title: "支付未完成", icon: "none" });
      },
    });
  },
});

这里有个最容易犯的错:在前端 success 回调里直接给用户开会员。前端的成功回调只代表微信客户端支付动作完成,不是可信的支付凭证,用户完全可以伪造。开通权益必须在第 4 步的服务端回调里做。

第 4 步:云函数接收支付回调,发货开权益

用户付款完成后,微信后台会自动调用你指定的 payCallback 云函数,参数里带着订单信息。这里才是真正发货的地方:

代码语言:js
复制
// 云函数 payCallback/index.js
const cloud = require("wx-server-sdk");
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV });
const db = cloud.database();

exports.main = async (event, context) => {
  const {
    return_code,      // 状态码
    out_trade_no,     // 商户订单号
    openid,           // 付款用户
    total_fee,        // 实付金额
  } = event;

  // 1. 幂等校验:订单已处理过就直接返回,避免重复开通
  const order = await db.collection("orders")
    .where({ outTradeNo: out_trade_no })
    .get();
  if (!order.data.length) return { errcode: 0 };
  if (order.data[0].status === "paid") return { errcode: 0 };

  // 2. 金额校验:实付金额要和订单金额一致
  if (total_fee !== order.data[0].totalFee) {
    return { errcode: 0 };   // 金额不符不发货,另记日志排查
  }

  // 3. 更新订单状态
  await db.collection("orders").doc(order.data[0]._id).update({
    data: { status: "paid", payTime: db.serverDate() },
  });

  // 4. 开通会员权益:按套餐时长延长到期时间
  const product = await db.collection("products")
    .doc(order.data[0].productId).get();
  const days = product.data.duration;
  const now = Date.now();
  const user = await db.collection("users").where({ openid }).get();
  const base = user.data.length && user.data[0].expireAt > now
    ? user.data[0].expireAt      // 未过期则续期
    : now;                       // 已过期则从现在算
  const expireAt = base + days * 24 * 60 * 60 * 1000;

  if (user.data.length) {
    await db.collection("users").doc(user.data[0]._id)
      .update({ data: { level: "vip", expireAt } });
  } else {
    await db.collection("users").add({
      data: { openid, level: "vip", expireAt, createTime: db.serverDate() },
    });
  }

  // 5. 必须返回成功,否则微信后台会重复调用此函数
  return { errcode: 0 };
};

这段代码里有三处是生产环境必须有的,不能省:幂等校验(防止回调重复触发导致重复开通)、金额校验(防止金额被篡改)、返回 errcode: 0(不返回微信会一直重试)。

五、用 AI 工具加速:可直接复制的需求

前面的结构想清楚之后,可以把下面这段整体交给接好云开发的 AI 工具,让它生成页面和基础代码,你再按第四节核对支付逻辑:

代码语言:txt
复制
用云开发做一个会员制微信小程序。

功能:
1. 首页:会员套餐列表(名称、价格、权益说明、时长),数据来自云数据库 products 集合
2. 套餐详情:展示权益,点击「立即开通」发起支付
3. 我的:显示当前会员等级、到期时间、历史订单列表
4. 微信登录:首次进入静默获取身份,云函数里用 OPENID 认人

实现要求:
- 原生小程序 + 云开发,不引第三方 UI 库,浅色卡片风格
- 登录走云开发身份,不要自建账号体系
- 支付走 cloudPay 云调用,云函数 makeOrder 下单、payCallback 接回调
- 价格从数据库查,不信任前端传值
- 集合三个:products(所有用户可读、仅创建者可写)、users(仅创建者可读写)、orders(仅创建者可读写)
- 会员等级与到期时间只能由 payCallback 云函数写入
- 生成完成后用微信开发者工具打开项目,并列出需要我手动完成的步骤

最后一句很重要——让 AI 明确告诉你哪些步骤它做不了(比如申请商户号、填商户号参数),避免你以为全自动完成了。

六、调试:支付链路怎么验证

支付不能直接拿真钱反复测,按这个顺序验证:

第 1 步:先验证云函数能调通。 在开发者工具里直接调用 makeOrder,看是否返回支付参数。报错多数集中在商户号填错、环境 ID 填错、小程序未开通支付。

第 2 步:用 1 分钱测真实链路。 totalFee 传 1(即 1 分钱),走完整支付流程。这是验证回调是否真的触发的唯一可靠方式。

第 3 步:查回调是否执行。 到云开发控制台看 payCallback 的云函数日志。如果订单状态没变成 paid,99% 是回调没触发或回调里报错了,日志里能看到具体堆栈。

第 4 步:验证幂等。 手动重复调用一次 payCallback(传相同订单号),确认不会重复开通会员、不会重复延长到期时间。

七、上线前必须核对的五件事

回调必须返回 { errcode: 0 }。不返回或返回其他值,微信后台会认为回调失败并重复调用,可能造成重复发货。

订单号不能重复。outTradeNo 重复会直接导致下单失败,时间戳加随机数是最低成本的方案。

金额单位是分。前端展示用元,传给接口用分,中间的换算只在一处做,不要散落在多个文件里。

权益写入只走服务端。再强调一次:前端支付成功回调不等于支付完成,开权益必须在 payCallback 里做。

提审与套餐。小程序提审时如实选择类目并提供支付相关资质;正式环境建议升级到付费套餐,并在上线前再过一遍数据库权限——确认没有集合是「所有用户可写」。

总结

云开发 CloudBase 把会员小程序的支付难点消掉了大半:云调用免去证书与签名,回调由云函数接收,不需要公网服务器。真正要你把握的是四件事——价格从数据库查、订单号不重复、权益只在服务端回调里写、回调做幂等和金额校验。按「身份 → 数据 → 订单 → 支付」的顺序建,用 1 分钱跑通真实链路,再去补提审资质,这条路是走得通的。支付资质、费率与结算规则以微信支付官方要求为准。

开通环境开始做你的会员小程序:云开发 CloudBase 购买页

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、先把会员小程序拆成四块
  • 二、开工前的前置条件
  • 三、数据建模:三个集合怎么设计
  • 四、支付链路:四步完整实现
    • 第 1 步:小程序端调用云函数下单
    • 第 2 步:云函数生成订单,返回支付参数
    • 第 3 步:小程序端调起微信支付
    • 第 4 步:云函数接收支付回调,发货开权益
  • 五、用 AI 工具加速:可直接复制的需求
  • 六、调试:支付链路怎么验证
  • 七、上线前必须核对的五件事
  • 总结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档