小程序接入微信支付集成指南
在 CloudBase 控制台创建「微信支付」集成后,系统会自动生成一个 HTTP 云函数(函数名形如 <集成名>-<随机串>,本文统称 pay-common)。本指南介绍如何基于该云函数在小程序端完成从下单到回调的完整支付闭环。
整体调用链路:
- 正向请求:小程序 →
wx.cloud.callHTTPFunction(平台自动鉴权 + 注入 openid)→pay-commonHTTP 云函数 → 微信支付 API - 异步回调:微信支付 → 集成中心(验签 + 解密)→
pay-common→ 业务侧
架构总览
┌──────────────────┐ ┌──────────────────┐
│ 微信小程序 │ wx.cloud.callHTTPFunction │ pay-common │
│ │ ──── POST /wx-pay/* ──────→ │ (HTTP 云函数) │
│ app.js │ ←─── { code, msg, data } ──│ SDK 自签 │
│ └ wx.cloud.init │ │ 直连微信支付 API │
│ │ 平台自动注入 header: └────────┬─────────┘
│ pay.js │ x-wx-openid │
│ └ callHTTPFunc │ x-wx-appid │ 统一下单
│ │ ▼
└──────────────────┘ ┌───────────────────────┐
▲ │ 微信支付 API │
│ │ api.mch.weixin.qq.com│
│ wx.requestPayment └───────────┬───────────┘
│ │ 异步支付回调
└────── 返回调起参数 ──────┐ ▼
│ ┌───────────────────────┐
│ │ 集成中心 │
│ │ (自动验签 + 解密) │
pay-common └───────────┬───────────┘
│ │ 明文转发
│ ▼
│ ┌───────────────────────┐
└──────── │ pay-common │
│ /wechatpay/order │
│ → orderService 处理 │
└───────────────────────┘
职责分工:
| 角色 | 职责 |
|---|---|
| 小程序 | 通过 wx.cloud.callHTTPFunction 调用 pay-common,平台自动注入 openid,无需登录、无需 Token |
| pay-common 云函数 | 从 x-wx-openid header 获取用户身份;处理下单、查单、退款等主动请求;接收并处理回调 |
| 微信支付 API | 支付业务实际执行方 |
| 集成中心 | 统一托管凭证;接收回调后完成验签与解密,并以明文转发至云函数 |
前置条件
| 项 | 要求 |
|---|---|
| 小程序 | 已通过微信认证,个人号小程序不支持开通支付 |
| 微信支付商户号 | 已申请并在商户平台完成与上述小程序的绑定 |
| 商户超管权限 | 用于下载 API 证书、设置 APIv3 密钥 |
| 小程序基础库版本 | ≥ 3.15.2(wx.cloud.callHTTPFunction API 的前提条件) |
| Node.js 18+ / CloudBase CLI | 本地开发与调试使用 |
| 微信开发者工具 | 最新稳定版 |
第一步 · 准备商户凭证
登录微信支付商户平台,以超级管理员身份按以下三节取值。获得的所有值将在第二步统一填入集成中心表单。
1.1 APIv3 密钥
路径:账户中心 → API 安全 → 设置 APIv3 密钥。
如首次使用,点击「设置」,自定义 32 位字母/数字组合。该密钥仅在设置时显示一次,需妥善保存。
APIv3 密钥用于回调的 AES-GCM 解密及部分 V3 API 响应的验签。如未设置,微信服务器将直接拒绝下发任何回调通知,商户平台「交易中心 → 通知查询」将显示"通知发送失败"。
1.2 商户 API 证书
路径:账户中心 → API 安全 → API 证书 → 申请/下载。
下载并解压后,需保留:
apiclient_key.pem:商户 API 私钥,用于下单请求签名- 40 位十六进制证书序列号(页面上展示),形如
36048761817F82958048330A6301E922AB28A04D
apiclient_cert.p12 与 apiclient_cert.pem 本指南不使用。
1.3 微信支付公钥
路径:账户中心 → API 安全 → 微信支付公钥管理 → 查看/下载公钥。
需保留:
wxp_pub.pem:微信支付公钥文件- 公钥 ID(页面上展示),形如
PUB_KEY_ID_0114...
公钥与平台证书的区别:微信支付 V3 验签历史上存在两种方案——「微信支付公钥」(一次下载,长期有效,推荐)与「微信支付平台证书」(X.509 证书,会过期,需调接口轮换)。如在集成中心表单中填写了微信支付公钥,pay-common 则用公钥方案;否则将按平台证书方案处理。
与商户 API 证书的区别:微信支付公钥用于验证微信下发给商户的响应与回调(代表微信侧身份);商户 API 证书则用于对商户发起的请求进行签名(代表商户侧身份)。两者作用相反,请勿混淆。
1.4 凭证清单
完成上述三节后,应已获得以下 7 项值,均将在第二步填入集成中心表单(字段名以 pay-common 实际注入的环境变量为准):
| # | 集成中心字段 / 环境变量 | 形态 | 取值出处 |
|---|---|---|---|
| 1 | appId | 小程序 AppID,形如 wxc1546068399a59fc | 微信公众平台 |
| 2 | merchantId | 10 位数字商户号 | 商户平台首页 |
| 3 | apiV3Key | 32 字符 APIv3 密钥 | 见 1.1 |
| 4 | merchantSerialNumber | 40 位十六进制证书序列号 | 见 1.2 |
| 5 | privateKey | apiclient_key.pem 完整内容(PEM 文本) | 见 1.2 |
| 6 | wxPayPublicKey | 微信支付公钥 PEM 内容 | 见 1.3 |
| 7 | wxPayPublicKeyId | 公钥 ID(PUB_KEY_ID_...) | 见 1.3 |
第二步 · 在 CloudBase 创建集成
2.1 进入集成中心
路径:云开发平台 → 模板与集成 → 集成中心 → 小程序微信支付 → 创建集成。
2.2 填写集成信息
控制台向导需填写以下内容:
- 集成名称(自定义,例如
miniapp-wxpay) - 第一步获取的 7 项凭证:
appId/merchantId/apiV3Key/merchantSerialNumber/privateKey/wxPayPublicKey/wxPayPublicKeyId
集成中心将统一托管上述凭证,并用于代处理回调的验签与解密。
2.3 自动生成云函数资源
创建成功后,系统自动完成两项操作:
- 按集成名称创建一个 HTTP 云函数(⚠️ 函数名形如
<集成标识>-<随机串>,例如miniapp-wxpay-rwmx67sc,本文统称pay-common)。 - 生成回调域名与具体回调 URL,用于接收微信支付的异步通知:
| 资源 | 说明 |
|---|---|
| 回调基础域名 | 形如 https://<集成标识>.integration-callback.tcloudbase.com |
| 支付回调 | /wechatpay/order |
| 退款回调 | /wechatpay/refund |
| 转账回调 | /wechatpay/transfer(当前版本暂不支持,集成中心尚未代处理转账回调;如有商家转账需求需自行接管) |
支付回调 URL 需同步填入微信支付商户平台的「支付结果通知 URL」(商户平台 → 产品中心 → 开发配置)。退款回调由 V3 退款接口请求中携带的 notify_url 决定,pay-common 已自动使用集成中心生成的对应 URL,无需手动填写。集成中心会将上述 URL 作为环境变量自动注入云函数(详见第三步)。
第三步 · 了解 pay-common 云函数
第二步创建集成时,平台已经把表单中的全部参数(AppID、商户号、APIv3 密钥、证书、私钥、回调地址等)作为环境变量注入到云函数。运行时通过 process.env 读取,业务代码中不会出现明文凭证,集成中心用户亦无需维护任何配置文件。
如需修改配置,进入「集成中心 → 对应集成 → 编辑」,保存后平台将自动重新部署云函数。
3.1 源码结构
如需查看或下载自动生成的云函数源码,可使用 tcb fn code <函数名> --download 或在控制台查看。目录结构如下:
pay-common/
├── index.js HTTP 云函数入口(CLI 部署入口)
├── app.js Express 应用入口,路由分发(_action)
├── scf_bootstrap HTTP 云函数启动脚本(监听 9000 端口)
├── bin/
│ └── www 本地/容器启动脚本(监听 3000 端口)
├── Dockerfile 云托管部署配置(集成中心模式下不使用)
├── cloudbaserc.json CloudBase CLI 部署配置(集成中心模式下无需修改)
├── package.json
├── config/
│ └── config.js 读取 process.env,处理 PEM 规范化与凭证校验
├── controllers/
│ └── payController.js 路由控制器(下单、查单、退款、转账、回调)
├── routes/
│ └── pay.js 对外路由定义
├── services/
│ ├── payService.js 统一入口,按 signMode 路由到策略
│ ├── orderService.js 回调处理(需对接业务系统)
│ └── strategies/
│ └── sdkStrategy.js SDK 自签名策略(下单、退款、转账的主动请求均走此策略)
├── utils/
│ ├── validator.js 参数校验
│ └── cloudbaseAuth.js 从请求 header 中提取 openid(x-wx-openid / JWT)
└── tests/ 单元/集成测试
3.2 支付相关路由
小程序通过 wx.cloud.callHTTPFunction 调用 pay-common,路由通过 path 参数走 Express 标准路由(如 /wx-pay/wxpay_order),平台自动注入 x-wx-openid header,无需登录、无需 Token。
💡 旧方案(
wx.request+ 云 API 网关 +body._action分发)仍可用但不推荐,callHTTPFunction更简洁。
路由路径 / _action | 类别 | 说明 |
|---|---|---|
wxpay_order | 下单 | JSAPI / 小程序下单(本指南主要使用) |
wxpay_query_order_by_out_trade_no | 查询 | 按商户订单号查单 |
wxpay_query_order_by_transaction_id | 查询 | 按微信订单号查单 |
wxpay_close_order | 关单 | 关闭订单(10 分钟未支付建议主动关闭) |
wxpay_refund | 退款 | 申请退款 |
wxpay_refund_query | 退款 | 查询退款 |
wxpay_transfer | 转账 | 商家转账。集成中心暂不支持转账回调 /wechatpay/transfer,发起接口可用,回调需自行接管 |
wxpay_transfer_bill_query | 转账 | 商户单号查转账单 |
wxpay_transfer_bill_query_by_no | 转账 | 微信单号查转账单 |
使用 callHTTPFunction 时,path 格式为 /wx-pay/<路由路径>,例如:path: '/wx-pay/wxpay_order'。
3.3 回调处理
services/orderService.js 是业务占位层,默认实现仅打印日志。上线前需结合业务数据库选型(MySQL、MongoDB、CloudBase 数据库等),在以 下回调处理方法中补齐业务处理逻辑:
| 方法 | 触发时机 | 典型实现 |
|---|---|---|
handlerUnified(params) | 下单成功后 | 将订单以 PENDING 状态写入数据库,保留 out_trade_no、金额、用户标识等字段 |
handlerUnifiedTrigger(params) | 支付回调 | 幂等校验订单状态、核对金额、将状态原子更新为 PAID,并触发发货等业务副作用 |
handlerRefund(params) | 发起退款成功后 | 将订单或退款单状态更新为「退款中」,记录 out_refund_no |
handlerRefundTrigger(params) | 退款回调 | 根据 refund_status(SUCCESS / CHANGE / REFUNDCLOSE)更新退款结果,处理账款回退、权益回收等 |
handlerTransfer(params, result) | 转账受理成功后 | 记录商户转账单号、微信转账单号与金额 |
handlerTransferTrigger(params) | 转账回调 | 根据 state(SUCCESS / FAIL 等)更新转账单最终状态。当前集成中心尚不支持转账回调代转发,如启用需自行接管 |
实现时需遵循以下原则:
- 尽早返回:所有
*Trigger回调需在 5 秒内返回{"code":"SUCCESS"},否则将触发微信重试(最长 24 小时,约 15 次)。幂等校验尽量同步完成,耗时副作用(发货、推送、外部 API 调用)异步派发到消息队列或定时任务。
第四步 · 接入小程序前端
pay-common 部署完成后,小程序侧有三种接入方式,按团队技术栈选择即可:
- 方式一:小程序自定义接入——原生开发者最常见路径,使用
wx.cloud.callHTTPFunction调用后端,平台自动注入 openid,无需登录流程。 - 方式二:使用官方示例工程——直接复用仓库内置的
examples/miniprogram/,开箱即用,适合快速验证或在 Demo 基础上改造。 - 方式三:在微搭低码(WeDa)中接入——零开发,把页面方法粘贴到微搭即可。
无论选哪种方式,都要先完成 4.1 的前置准备;接口契约见 3.2 路由清单与 3.3 回调处理。
4.1 前置准备
确认基础库版本
在 project.config.json 中确认 libVersion ≥ 3.15.2(wx.cloud.callHTTPFunction 最低版本要求)。
初始化云开发
在 app.js 的 onLaunch 中调用 wx.cloud.init(),后续即可使用 wx.cloud.callHTTPFunction:
App({
onLaunch() {
wx.cloud.init({
env: 'your-env-id', // ⚠️ 替换为你的云开发环境 ID
traceUser: true,
})
},
})
💡
callHTTPFunction无需开启 CloudBase Auth 身份源、无需安装@cloudbase/js-sdk、无需构建 npm。
4.2 方式一:小程序自定义接入
适合原生小程序自研工程。通过 wx.cloud.callHTTPFunction 调用 pay-common,平台自动注入 openid,无需登录流程、无需 Token 管理。
关键约束:
ENV_ID:云开发环境 ID,在控制台 → 环境概览 → 环境 ID 中获取,形如test-wxpay-5gy4ugzreef15cfeFN_NAME:集成创建后自动生成的 HTTP 云函数名,在控制台 → 集成中心 → 对应集成的详情页或云函数列表中查看,形如miniapp-wxpay-rwmx67sc- 下单请求体最少包含 3 个字段:
description/out_trade_no/amount amount.total单位为分(1 分 = 0.01 元),out_trade_no必须全局唯一- 无需传
payer.openid,后端自动从平台注入的x-wx-openidheader 获取 callHTTPFunction返回结构为{ code: 0, msg: 'success', data: { status: 200, data: { timeStamp, nonceStr, package, signType, paySign } } }。支付参数取res.data.data(代码中用res.data?.data || res.data做兼容解包)
// ============ app.js ============
const ENV_ID = 'your-env-id'
const FUNCTION_NAME = 'pay-common' // 集成中心创建后生成的实际函数名
App({
globalData: {
envId: ENV_ID,
functionName: FUNCTION_NAME,
},
onLaunch() {
if (ENV_ID === 'your-env-id') {
wx.showModal({
title: '配置未完成',
content: '请先在 app.js 中将 ENV_ID 替换为你的云开发环境 ID',
showCancel: false,
})
return
}
// 初始化微信云开发(callHTTPFunction 需要先 init)
wx.cloud.init({
env: ENV_ID,
traceUser: true,
})
console.log('[App] 云开发初始化完成, env:', ENV_ID)
},
})
// ============ 页面:发起一次完整支付 ============
const app = getApp()
/**
* 封装 callHTTPFunction 调用
* @param {string} action - 路由路径名,如 'wxpay_order'
* @param {object} data - 请求参数
*/
function callPayCommon(action, data) {
const { functionName, envId } = app.globalData
return new Promise((resolve, reject) => {
wx.cloud.callHTTPFunction({
name: functionName,
config: { env: envId },
method: 'POST',
header: { 'Content-Type': 'application/json' },
path: `/wx-pay/${action}`, // Express 标准路由
data,
success(res) {
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(res.data) // 直接是 { code, msg, data },无需解包
} else {
reject({ code: -1, msg: `HTTP ${res.statusCode}`, data: res.data })
}
},
fail: reject,
})
})
}
async function pay() {
const out_trade_no = 'ORDER_' + Date.now()
// 1. 调用云函数下单(无需传 payer.openid,平台自动注入 x-wx-openid)
const res = await callPayCommon('wxpay_order', {
description: '测试商品',
out_trade_no,
amount: { total: 20, currency: 'CNY' }, // 0.2 元
// ❌ 不需要传 payer.openid,后端从 x-wx-openid header 自动获取
})
if (res.code !== 0) {
wx.showToast({ title: res.msg || '下单失败', icon: 'error' })
return
}
const p = res.data?.data || res.data
// p = { timeStamp, nonceStr, package, signType, paySign }
// 2. 调起微信支付
wx.requestPayment({
timeStamp: String(p.timeStamp),
nonceStr: p.nonceStr,
package: p.package, // 形如 'prepay_id=wx20...'
signType: p.signType || 'RSA',
paySign: p.paySign,
success() {
// 支付成功:前端仅用于更新 UI,最终以服务端回调为准
// 建议 1-2 秒后调用 wxpay_query_order_by_out_trade_no 主动查单兜底
},
fail(err) {
// 支付失败或用户取消:可通过 err.errMsg 判断是否为 cancel
},
})
}
实现要点:
callHTTPFunction路由通过path参数走 Express 标准路由(如/wx-pay/wxpay_order),无需_action字段out_trade_no通过闭包变量保留,查单时需要复用package直接使用接口返回值,请勿自行拼接prepay_id=...,pay-common 已完成拼装- 最终支付状态以服务端回调为准,前端
success仅用于更新 UI;服务端收到回调后再执行发货等副作用
4.3 方式二:使用官方示例工程
适合不想自行搭脚手架、想快速跑通完整链路的场景。官方仓库提供完整的小程序示例:awesome-cloudbase-examples/integration/cloudbase-wx-pay/examples(同时包含一份 React Web 测试页)。本项目 examples/miniprogram/ 目录亦内置了同一份小程序示例。
一次性配置
- 导入工程:微信开发者工具 → 右上角「导入项目」→ 选择
examples/miniprogram/目录。 - 填写关键参数(⚠️ 缺一不可,否则调用 404):
app.js顶部ENV_ID→ 实际云开发环境 IDapp.js顶部FUNCTION_NAME→ 必须改为集成创建后生成的真实函数名(在控制台 → 集成中心 → 对应集成详情页中查看,形如miniapp-wxpay-rwmx67sc,而非默认的pay-common)project.config.json中的appid→ 实际小程序 AppIDproject.config.json中的libVersion→ 确认 ≥3.15.2
💡 示例工程使用
wx.cloud.callHTTPFunction,无需npm install、无需构建 npm、无需安装任何依赖。
模拟器自检
点击左上角「编译」。Console 中能看到云开发初始化成功即说明配置正常。
模拟器可用于验证:云开发初始化是否成功、下单是否返回 prepay_id、页面交互是否正常。但模拟器无法完成真实支付——callHTTPFunction 在模拟器中注入的 openid 可能为测试值,下单会被微信拒绝;即便绕过该限制,wx.requestPayment 也需要在手机微信中输入支付密码,模拟器不具备此能力。

真机支付测试
- 右上角「真机调试」→ 手机微信扫码打开。
- 在手机端点击「微信支付」按钮 → 微信弹出密码界面 → 输入密码完成支付。
4.4 方式三: 在微搭低码(WeDa)中接入
适合希望零开发、用低码搭建支付页面的场景。微搭低码可直接复用 pay-common,与原生小程序一样使用 wx.cloud.callHTTPFunction 调用后端,平台自动注入 openid,无需登录流程、无需 Token 管理。
链路示意:
微搭页面方法 → wx.cloud.callHTTPFunction(平台自动注入 x-wx-openid)
→ path: /wx-pay/wxpay_order
→ 解包返回,调 wx.requestPayment 拉起支付
关键约束:
- 无需
$w.auth、无需 accessToken、无需 Bearer 鉴权——callHTTPFunction已自动处理身份 - 无需传
payer.openid——后端从x-wx-openidheader 自动获取 - pay-common 函数名使用集成创建后生成的真实函数名(形如
pay-050603-mdd8hhn8-demo-scfweb) - 微搭构建的小程序基础库版本需 ≥ 3.15.2
页面方法示例(粘贴到微搭页面 → 方法 → 自定义方法):
/**
* 微搭页面方法:发起一次完整支付
* 文档:https://cloud.tencent.com/document/product/1301/57912
*/
export default async function ({ event, data }) {
const out_trade_no = 'ORDER_' + Date.now()
// 1. 调用 pay-common 下单(无需传 openid,平台自动注入 x-wx-openid)
const orderRes = await new Promise((resolve, reject) => {
wx.cloud.callHTTPFunction({
name: 'pay-common', // ⚠️ 替换:集成创建后生成的实际函数名
config: {
env: 'your-env-id', // ⚠️ 替换:云开发环境 ID
},
method: 'POST',
header: {
'Content-Type': 'application/json',
},
path: '/wx-pay/wxpay_order', // Express 标准路由
data: {
description: '测试商品',
out_trade_no,
amount: { total: 20, currency: 'CNY' }, // 0.2 元
// ❌ 不需要传 payer.openid,后端从 x-wx-openid header 自动获取
},
success: resolve,
fail: reject,
})
})
const body = orderRes.data
if (body.code !== 0) {
wx.showToast({ title: body.msg || '下单失败', icon: 'error' })
return
}
const p = body.data && body.data.data ? body.data.data : body.data
// p = { timeStamp, nonceStr, package, signType, paySign }
// 2. 调起微信支付
wx.requestPayment({
timeStamp: p.timeStamp,
nonceStr: p.nonceStr,
package: p.package, // 形如 'prepay_id=wx20...'
signType: p.signType || 'RSA',
paySign: p.paySign,
success() {
// 前端仅用于更新 UI,最终以服务端回调为准
// 建议 1-2 秒后用 wxpay_query_order_by_out_trade_no 主动查单兜底
},
fail(err) {
// 用户取消时 err.errMsg 含 'cancel',可与真实失败区分
},
})
}
排查建议:
- 若
callHTTPFunction is not a function:检查微搭构建的小程序基础库版本是否 ≥ 3.15.2。 - 若下单返回
appid 和 openid 不匹配:核对集成中心的appId与微搭所用小程序 AppID 是否同一份,参见本文 FAQ。 - 若返回 404:检查
name(函数名)和path(路由路径)参数是否正确。