支付状态同步-异步回调与主动查单兜底
不能只靠回调
支付平台一般是异步回调通知商户:用户付完钱,平台往你的 /notify 地址 POST 一个请求,告诉你”这笔订单付了”。
但回调这东西不能全信。网络抖动、服务器重启、notify-url 改了、DNS 出问题、甚至平台那边延迟,都可能让回调丢掉或者晚到。只靠回调,迟早会遇到”用户钱都付了,你这边还不知道”这种情况。
所以支付状态同步一般做成:异步回调(推)+ 主动查单(拉),两条腿走路。
推和拉各管什么
支付平台 商户服务 |
- 推(回调):实时性好,正常情况用户付完几秒就通知到了。
- 拉(查单):兜底,处理回调丢了、晚了、或者用户主动刷新页面的情况。
回调与查单共用同一份落账逻辑
不管支付结果是从回调来的还是查单来的,最后都得进同一个落账函数。这是数据一致性的根本。
如果回调写一套、查单写另一套,时间一长,”回调能过、查单过不了”或者两边状态对不上这种 bug 迟早会出现。尤其金额校验、幂等判断、发放权益这几步,必须收到一个函数里。
回调入口 ──┐ |
markPaid 内部依次做:状态机检查 → 金额校验 → 幂等判断 → 更新订单 → 发放权益。这个函数只写一份、测透,两条入口都调它,谁也不许自己另起一套。
查单什么时候触发
常见的三种时机:
- 用户主动触发:页面上点”我已支付”,前端调你的查单接口,你再回头去查支付平台。
- 轮询:客户端等支付的时候定时轮询你的接口,你这边定期查平台。
- 定时补偿任务:扫库里”挂了很久、快过期”的订单,批量去查单。
三种可以叠加着用。用户主动触发最快,轮询覆盖一般场景,定时任务捞异常单。
回调和查单返回怎么处理
回调收到后,得按平台要求的格式回一个成功应答(微信是 {"code":"SUCCESS"}),不然平台会认为通知失败、接着重试。
查单更像普通接口调用:拿到状态,如果已支付就调共用的落账函数;没付就记一下状态,接着等。
对账
推 + 拉能盖住大多数情况,但还是不够保险。每天都得跑一遍对账:
- 把本地所有已支付订单和平台的账单核对一遍;
- 挑出”本地已付但平台没记录”或”平台已付但本地没处理”的异常单;
- 这些单子走人工或自动的退款 / 补单流程。
对账这道别图省事省掉,它是你最后能发现钱对不上的机会。
回过头看,其实就是不把鸡蛋放一个篮子:回调来得快但靠不住,那就再主动查单补一道;两边的钱最后都得进同一个落账函数,免得对不上。哪怕这样还是会有漏网的,所以每天再跑一遍对账兜个底。推、拉、对账,三样凑齐了,支付状态同步这事儿才算踏实。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 CYK's Blog!
评论
