做小程序这几年,支付对接是被问得最多、也是返工最多的一块。尤其在北京,客户对合规和体验都抠得细,一个支付流程没打磨好,上线后投诉来得比流量还快。这篇就把我们知码客团队在真实项目里踩过的坑、绕过的弯,摊开来聊一聊。

先想清楚:你要的是哪种支付
很多需求方一上来就说“我要接微信支付”,但微信支付本身分好几种产品形态,选错了后面全是麻烦:
- JSAPI 支付:小程序内下单的主流方式,必须绑定商户号并关联 AppID。
- 小程序虚拟支付:涉及虚拟商品(课程、会员、充值)时规则完全不同,别拿实物那套硬套。
- 企业付款到零钱:做分销、返现、退款时才会用到,开通门槛不低。
我们去年给北京朝阳一家做亲子活动的客户做小程序,他们一开始想做“充值卡+线下核销”,聊到一半才发现虚拟支付和实物支付混着走,账都对不齐。后来拆成两套账户体系,支付链路才理顺。这一步想不明白,代码写得再漂亮也是白搭。
商户号与 AppID 的绑定,是第一个拦路虎
小程序要调起支付,商户号和 AppID 必须在微信支付商户平台完成关联,而且关联后还要在小程序后台确认。听起来简单,实操里经常卡在:
- 主体不一致:小程序主体是 A 公司,商户号是 B 公司,关联直接被拒。
- 子商户模式:服务商代开发时,子商户进件资料不全,审核来回折腾一两周。
- AppID 填错:把公众号的 AppID 填进商户平台,调起支付时报“appid 不匹配”。
北京这边不少客户是集团下面多个主体,签约主体和运营主体经常不是同一个。我的建议是:在写第一行业务代码之前,先把主体关系、结算账户、发票抬头全部对一遍,否则后面改起来牵一发动全身。
统一下单与签名,细节决定成败
服务端调用统一下单接口,最容易出问题的是签名。微信支付 v2 用 MD5/HMAC-SHA256,v3 用 RSA,两套逻辑别混。下面是我们项目里常用的 v3 下单请求骨架(Node.js 示例,仅示意流程):
const axios = require('axios')
const crypto = require('crypto')
async function createOrder({ outTradeNo, openid, totalFee, notifyUrl }) {
const url = '/v3/pay/transactions/jsapi'
const body = JSON.stringify({
appid: APPID,
mchid: MCHID,
description: '活动报名费',
out_trade_no: outTradeNo,
notify_url: notifyUrl,
amount: { total: totalFee, currency: 'CNY' },
payer: { openid }
})
const timestamp = Math.floor(Date.now() / 1000).toString()
const nonceStr = crypto.randomBytes(16).toString('hex')
const message = `POST\n${url}\n${timestamp}\n${nonceStr}\n${body}\n`
const signature = crypto
.createSign('RSA-SHA256')
.update(message)
.sign(privateKey, 'base64')
const authorization =
`WECHATPAY2-SHA256-RSA2048 mchid="${MCHID}",nonce_str="${nonceStr}",` +
`signature="${signature}",timestamp="${timestamp}",serial_no="${SERIAL_NO}"`
const res = await axios.post('https://api.mch.weixin.qq.com' + url, body, {
headers: { Authorization: authorization, 'Content-Type': 'application/json' }
})
return res.data.prepay_id
}
拿到 prepay_id 后,小程序端还要再签一次名(paySign),字段顺序、大小写、换行符都不能错。我们遇到过客户自己拿 Postman 测通了,一放进小程序就报“签名错误”,最后发现是前端把时间戳当数字传了,而签名要求字符串。
回调通知:别把“收到”当成“处理完”
支付成功后的异步通知,是账务准确性的命门。几个硬性要求:
- 必须验签,v3 要校验 Wechatpay-Signature 和平台证书序列号。
- 必须做幂等,同一笔订单可能收到多次通知。
- 处理成功要返回 200 和指定 JSON,否则微信会持续重试。
- 金额、订单号要和本地订单二次核对,别信回调里的数字就直接发货。
有个北京做餐饮外卖的小程序,早期回调里直接改订单状态,结果网络抖动导致重复通知,同一单被核销了两次,月底对账差了小两千。后来加上“状态机+唯一索引”才彻底解决。支付无小事,账对不上,信任就没了。
本地场景里的几个实际建议
北京客户业务节奏快,很多是线下门店、活动报名、会员储值这类场景。结合我们做过的项目,给几条落地建议:
- 退款接口提前接好,别等客户投诉了才临时加,退款也要走异步回调。
- 对账文件下载做成定时任务,每天自动拉取,人工核对只做异常抽查。
- 测试环境用沙箱或小额真实支付,别拿生产商户号随便试。
- 把支付相关的日志单独打一份,出问题时能按订单号快速定位。
知码识途,匠心铸客。支付这条链路,用户看不见代码,但每一次“支付成功”的提示,都是对我们工作的投票。
如果你正在北京做小程序,或者手里的项目卡在支付对接这一环,欢迎来知码客聊聊。我们不做花哨的承诺,只把每一行和钱打交道的代码,写得稳一点、再稳一点。

评论 (0)
还没有评论,快来抢沙发吧~