小程序如何对接微信支付:从商户号到第一笔回调
【摘要】 小程序如何对接微信支付:从商户号到第一笔回调小程序接入微信支付,本质不是「前端调一个 API」这么简单,而是后端下单 + 前端调起 + 异步回调验签三段式闭环。任何一段没接稳,都会出现「钱扣了订单没更新」「回调收不到」「签名错误」等经典问题。下面按实际落地顺序讲一遍。一、前置条件:先把账号关系理清在小程序里用微信支付,前提不是会写代码,而是账号资质要对:小程序主体完成微信认证(个人主体开不了...
小程序如何对接微信支付:从商户号到第一笔回调
小程序接入微信支付,本质不是「前端调一个 API」这么简单,而是后端下单 + 前端调起 + 异步回调验签三段式闭环。任何一段没接稳,都会出现「钱扣了订单没更新」「回调收不到」「签名错误」等经典问题。
下面按实际落地顺序讲一遍。
一、前置条件:先把账号关系理清
在小程序里用微信支付,前提不是会写代码,而是账号资质要对:
- 小程序主体完成微信认证(个人主体开不了微信支付)
- 申请微信支付商户号,支持企业、个体工商户、事业单位等
- 小程序 AppID 与商户号互相绑定
- 商户平台配置 APIv3 密钥、下载商户 API 证书
💡 小程序支付和公众号 JSAPI 支付共用一套下单接口,但小程序不需要配置 JSAPI 支付授权目录。
二、整体流程全景
标准链路只有 5 步:
- 用户点「立即支付」,小程序把订单信息发给自家后端
- 后端调用微信支付 JSAPI / 小程序下单接口,拿到
prepay_id - 后端按规则签名,把
timeStamp / nonceStr / package / signType / paySign返给前端 - 前端调
wx.requestPayment拉起收银台 - 用户支付完成后,微信回调后端
notify_url,后端验签、解密、更新订单
前端回调只负责「页面跳转体验」,订单状态一律以后端回调 + 查单接口为准。
三、后端:调用 JSAPI 下单
接口地址
POST https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
请求头要带
Authorization(V3 签名)、Accept 和 Content-Type 都是 application/json。核心参数
|
参数
|
说明
|
|---|---|
appid |
小程序 AppID
|
mchid |
商户号
|
description |
商品描述,用户账单可见
|
out_trade_no |
商户订单号,同商户号下唯一
|
notify_url |
公网 HTTPS,不能带端口、不能重定向
|
amount.total |
金额,单位分
|
payer.openid |
支付用户的 openid
|
示例 body:
{
"appid": "wx1234567890",
"mchid": "1900000109",
"description": "商城-订单支付",
"out_trade_no": "ORDER20261020001",
"notify_url": "https://api.example.com/wxpay/notify",
"amount": {
"total": 1990,
"currency": "CNY"
},
"payer": {
"openid": "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"
}
}
微信返回里取
prepay_id 即可。⚠️out_trade_no必须唯一,重复会报订单号冲突;超时未付的订单应先关单再用新订单号重下。
四、前端:wx.requestPayment 调起支付
后端拿到
prepay_id 后,还要按 V3 规则生成前端签名(参与签名字段:appId、timeStamp、nonceStr、package),签名算法用 RSA。前端拿到的参数结构:
wx.requestPayment({
timeStamp: '1697780000',
nonceStr: '5K8264ILTKCH16CQ2502SI8ZNMTM67VS',
package: 'prepay_id=wx2026102000001234567890',
signType: 'RSA',
paySign: 'oR9d8PuhnIc+YZ8cB...',
success(res) {
// 仅做页面跳转,不代表支付成功
},
fail(res) {
if (res.errMsg.includes('cancel')) {
// 用户取消
}
}
})
几个容易踩的点:
package值必须是prepay_id=xxx完整串,不是只传 idsignType与后端签名方式保持一致,V3 用 RSA,别套旧教程的 MD5success回调只能说明「拉起支付没报错」,不能证明到账
五、后端:接收支付回调(最关键)
用户付完钱,微信会 POST 到
notify_url,报文是加密的。1. 验签
回调 HTTP 头里带四个字段:
Wechatpay-SerialWechatpay-SignatureWechatpay-TimestampWechatpay-Nonce
用平台证书公钥对「时间戳 + 随机串 + body 原文」验签,确认确实是微信发的。
2. 解密
body 里的
resource.ciphertext 是 AES-256-GCM 加密,用 APIv3 密钥解密,拿到:{
"out_trade_no": "ORDER20261020001",
"transaction_id": "4200001234567890",
"trade_state": "SUCCESS",
"amount": { "total": 1990 }
}
3. 业务处理 + 应答
正确处理顺序:
- 验签
- 解密
- 查本地订单,做幂等判断(已处理直接返回成功)
- 校验金额、订单号是否对得上
- 更新订单状态、发货、记日志
- 5 秒内返回 HTTP 200/204
// 成功不应答包体,状态码 200 即可
如果业务处理重(发券、推消息、扣库存),先落库标记「已收到通知」,再丢队列异步跑,别在回调里同步干重活,否则微信会超时重发。
⚠️ 微信回调会重复推,必须幂等;超时未应答会按 15s/30s/3m… 重发最多 15 次。
六、兜底:别只信回调
生产环境正确做法是「回调 + 主动查单」双保险:
- 前端
requestPayment返回后,调后端查单接口确认状态 - 后端对「已创建但未支付」的订单,定时跑批查
查询订单接口 - 超时未付调用关单接口,释放库存
七、常见坑速查
- 签名错误 → 检查 appid 是不是小程序 appid、参数大小写、key/v3密钥用错、MD5/RSA 混用
- 回调收不到 → notify_url 非公网、带端口、HTTP、服务器防火墙拦了
- 前端 paySign 报错 → package 没带
prepay_id=前缀 - 交易类小程序调不起支付 → 未接入订单发货管理,被公众平台限权
- 金额对不上 → 前端展示用元,后端传分,别直接透传
八、最小落地清单
接入前对着勾一遍:
- [ ] 小程序已认证、商户号已绑定 AppID
- [ ] APIv3 密钥和商户证书已配
- [ ] 后端能调通 JSAPI 下单拿到 prepay_id
- [ ] 前端 wx.requestPayment 参数由后端签名
- [ ] notify_url 公网 HTTPS、幂等处理
- [ ] 回调验签 + 解密 + 5 秒内应答
- [ ] 订单状态以后端查单/回调为准
跑通这一条链路,小程序支付就算真正落地了。后面要加分账、退款、对账账单,都是在「下单 → 回调」这个骨架上挂模块,不会动摇主流程。
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)