上周三晚上十点多,朋友发来语音,语气有点急:"客户在小程序里付了钱,后台订单还是'待支付',钱去哪了?"我打开他小程序的支付日志一看,微信支付回调压根没到服务器——典型的回调掉单。这已经不是第一次遇到这种问题了,这篇把小程序支付回调从配置到排障的完整链路记录下来,给同样踩坑的朋友参考。
微信支付成功后,微信服务器会向商户后台的 notify_url 发送一个 POST 请求,携带支付结果。商户后台验签通过后,把订单状态更新为"已支付"。整个链路是:
微信支付成功
↓
微信服务器 POST notify_url
↓
商户后台验签(sign 比对)
↓
更新订单状态为"已支付"
↓
返回 success 应答掉单通常发生在两个环节:一是回调没发出来(notify_url 配错或不可达),二是回调发了但商户后台没正确处理(验签失败、响应超时、状态更新失败)。
微信支付的通知机制是"不保证只发一次":支付成功、商户返回非 success、网络异常都会触发重发,最多重发 9 次,间隔递增。所以商户后台处理回调必须幂等:
伪代码示例:
def handle_pay_notify(notify_data):
if not verify_sign(notify_data): # 验签
return 'fail'
order = get_order(notify_data['out_trade_no'])
if order.status == 'PAID': # 幂等判断:已支付直接返回
return 'success'
if order.status != 'PENDING':
return 'success'
update_order_status(order, 'PAID')
return 'success'回调请求里带 sign 字段,后台要用 API 密钥对关键参数排序拼接后计算签名比对。验签失败必须返回 fail 且不能更新订单,否则存在伪造回调风险。这里有个踩坑:参数拼接要去掉空值字段、按字典序排序,拼接字符串的格式必须和官方文档完全一致,多一个空格都会验签失败。
回调再稳也有丢失可能(比如服务器重启、网络分区),所以一定要有对账任务:
这次给朋友处理用的后台是乔拓云的轻应用,它的支付设置里直接把回调地址、密钥配置做成了可视化表单,省去了自己写回调接收逻辑的部分,我只需要把精力放在验签和幂等这两块业务逻辑上。
以上是个人实践记录,各平台具体功能以官方实时信息为准。
补充一个开放问题:你在生产环境里遇到过哪些诡异的回调掉单场景,最后是怎么定位的?
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。