适用对象:小程序前端开发
版本:v1.0 | 更新日期:2026-07-09
Base URL:http://localhost:8080(开发环境)
小程序支付使用微信 JSAPI 支付,与扫码支付(NATIVE)流程完全不同:不是展示二维码,而是一键调起微信支付面板。
| WECHAT / ALIPAY(扫码) | WECHAT_MINIAPP(小程序) | |
|---|---|---|
| 用户操作 | 展示二维码 → 扫码付款 | 直接弹出微信支付面板 |
| 返回凭证 | qrCodeBase64(Base64图片) |
miniAppPayParams(签名对象) |
| openId | 不需要 | 自动从用户记录读取(登录时已存储) |
| 下单接口 | TradeTypeEnum.NATIVE |
TradeTypeEnum.JSAPI |
t_user.wechat_mini_open_id 不为空"未获取到小程序 openId,请先通过小程序登录"openId 在登录时通过 code2Session 获取并持久化,支付时从数据库直接读取,不需要重复 wx.login 授权// ──── 步骤 1:用户登录(已有流程,无需改动)────
// 小程序端调用 wx.login() + 后端 miniappUnifiedLogin
// → 后端 code2Session 获取 openId 并存入 t_user.wechat_mini_open_id
// → 返回 JWT token(后续请求携带)
// ──── 步骤 2:创建小程序支付订单 ────
const res = await request({
url: '/api/payment/order/create',
method: 'POST',
header: { Authorization: `Bearer ${token}` },
data: {
planId: 1,
channel: 'WECHAT_MINIAPP' // ⚠️ 不传 openid,后端从用户记录读取
}
})
// ──── 步骤 3:调起微信支付面板 ────
const params = res.data.miniAppPayParams
wx.requestPayment({
timeStamp: params.timeStamp,
nonceStr: params.nonceStr,
package: params.package, // "prepay_id=wx..."
signType: params.signType, // "RSA"
paySign: params.paySign,
success(res) {
// 支付成功 → 查询订单确认状态
queryOrderStatus(orderNo)
},
fail(err) {
// 用户取消或支付失败
console.log('支付取消', err)
}
})
GET /api/payment/plans
无需认证
响应:
{
"code": 200,
"data": [
{
"id": 1,
"planCode": "MONTHLY_PRO",
"planName": "高级会员·月卡",
"membershipLevel": "PRO",
"price": 29.90,
"originalPrice": 59.90,
"durationDays": 30,
"sortOrder": 3,
"status": 1,
"description": "每天不限量· 1个月29.9(原价59.9)"
}
]
}
POST /api/payment/order/create
需要认证(Header: Authorization: Bearer {token})
请求体:
{
"planId": 1,
"channel": "WECHAT_MINIAPP"
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| planId | Long | 是 | 支付方案ID(从 4.1 接口获取) |
| channel | String | 是 | 支付渠道,小程序固定传 WECHAT_MINIAPP |
⚠️ 不需要传
openid,后端自动从当前登录用户的t_user.wechat_mini_open_id读取。
响应(WECHAT_MINIAPP — 小程序支付):
{
"code": 200,
"data": {
"orderNo": "OP1234567890123456",
"planName": "高级会员·月卡",
"amount": 29.90,
"channel": "WECHAT_MINIAPP",
"status": "PENDING",
"qrCodeBase64": null,
"payUrl": null,
"miniAppPayParams": {
"appId": "wxabc123...",
"timeStamp": "1752060000",
"nonceStr": "a1b2c3d4e5f6...",
"package": "prepay_id=wx1234567890...",
"signType": "RSA",
"paySign": "XXXX..."
},
"expireTime": "2026-06-30T22:00:00",
"expireHint": "请在15分钟内完成付款,超时订单将自动过期",
"createTime": "2026-06-30T21:45:00"
}
}
响应字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| orderNo | String | 订单号(后续查询/切换渠道用) |
| planName | String | 方案名称 |
| amount | BigDecimal | 金额(元) |
| channel | String | 支付渠道 |
| status | String | PENDING-待支付 / PAID-已支付 / EXPIRED-已过期 |
| qrCodeBase64 | String | 小程序支付为 null |
| payUrl | String | 小程序支付为 null |
| miniAppPayParams | Object | 小程序支付参数,用于调起微信支付 |
| expireTime | String | 过期时间(创建后15分钟) |
| expireHint | String | 过期提示文案 |
| createTime | String | 创建时间 |
| 字段 | 说明 | wx.requestPayment 参数 |
|---|---|---|
| appId | 小程序AppID | ❌ 不传(wx.requestPayment 不需要) |
| timeStamp | 时间戳(秒,字符串) | ✅ timeStamp |
| nonceStr | 随机字符串(32位hex) | ✅ nonceStr |
| package | 格式 prepay_id=xxx |
✅ package |
| signType | 固定 RSA |
✅ signType |
| paySign | RSA-SHA256 签名 | ✅ paySign |
POST /api/payment/order/{orderNo}/switch-channel
需要认证
业务场景: 用户创建订单后,如需从扫码支付切换为小程序支付(或反之),调用此接口。
不关闭原渠道订单,以第一个支付成功渠道为准,后续重复支付自动退款。
请求体:
{
"channel": "WECHAT_MINIAPP"
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| channel | String | 是 | 新支付渠道:WECHAT / ALIPAY / WECHAT_MINIAPP |
同样不传
openid,后端自动从用户记录读取。
响应: 同 4.2 创建订单(根据新渠道返回对应格式)
切换渠道示例:
// 从 WECHAT_MINIAPP 切换到 WECHAT 扫码:
// → 返回 qrCodeBase64(展示二维码让用户扫码)
// 从 WECHAT 切换到 WECHAT_MINIAPP:
// → 返回 miniAppPayParams(直接调起支付面板)
GET /api/payment/order/{orderNo}
需要认证
响应:
{
"code": 200,
"data": {
"orderNo": "OP1234567890123456",
"planName": "高级会员·月卡",
"amount": 29.90,
"channel": "WECHAT_MINIAPP",
"status": "PAID",
"qrCodeBase64": null,
"payUrl": null,
"expireTime": "2026-06-30T22:00:00",
"expireHint": null,
"createTime": "2026-06-30T21:45:00"
}
}
支付成功后
status变为PAID,可跳转至支付成功页。
GET /api/payment/orders
需要认证
响应:
{
"code": 200,
"data": [
{
"orderNo": "OP1234567890123456",
"planName": "高级会员·月卡",
"amount": 29.90,
"channel": "WECHAT_MINIAPP",
"status": "PAID",
"createTime": "2026-06-30T21:45:00"
}
]
}
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
未获取到小程序 openId |
用户未通过小程序登录 | 先调用小程序登录接口 |
用户不存在 |
userId 无效 | 检查 JWT token 是否有效 |
微信支付未配置 |
payment.wechat 参数缺失 | 联系后端检查配置 |
支付方案不存在 |
planId 无效 | 检查 planId 是否正确 |
支付方案已下架 |
方案已停用 | 提示用户该方案已下架 |
支付订单已过期 |
超过15分钟未支付 | 重新创建订单 |
| code | 说明 |
|---|---|
| 2001 | 支付订单不存在 |
| 2002 | 支付订单已过期 |
| 2003 | 支付金额不正确 |
| 2004 | 不支持该支付渠道 |
| 2005 | 支付失败 |
| 2006 | 退款失败,请重试 |
| 2007 | 支付方案不存在 |
| 2008 | 支付方案已下架 |
| 2010 | 支付渠道未配置 |
以下为后端配置,供联调参考:
# application.yml
wechat:
miniapp:
app-id: wxMINIAPP123... # 小程序appId(登录用)
app-secret: secret... # 小程序appSecret(登录用)
payment:
miniapp:
app-id: wxMINIAPP123... # 支付签名用appId(必须与小程序一致)
wechat:
app-id: wxOFFICIAL... # Native扫码用appId(可与上面不同)
mch-id: 1234567890 # 商户号(Native + JSAPI 共用)
# ... 密钥、证书等
| 接口 | 方法 | 认证 | 说明 |
|---|---|---|---|
/api/payment/plans |
GET | 否 | 获取支付方案列表 |
/api/payment/order/create |
POST | 是 | 创建订单(channel=WECHAT_MINIAPP) |
/api/payment/order/{orderNo}/switch-channel |
POST | 是 | 切换支付渠道 |
/api/payment/order/{orderNo} |
GET | 是 | 查询订单状态 |
/api/payment/orders |
GET | 是 | 我的订单列表 |
所有接口返回格式:
{
"code": 200,
"message": "success",
"data": {}
}
| code | 说明 |
|---|---|
| 200 | 成功 |
| 400 | 参数错误 |
| 401 | 未认证(Token 无效或过期) |
| 403 | 无权限 |
| 500 | 服务器内部错误 |