常见问题排查

按症状对号入座。每条都按"先定位、再解决"给步骤,走完仍未解决就把报错原文 + 请求时间 + 单号发给顽兔技术支持(不要发 api_secret)。

调接口报 40001(签名错误)

  1. 确认 api_secret 没拿混:联调、生产是两套凭据,最常见就是环境串了
  2. 确认用的是 SDK 而不是自己拼签名。用 SDK 时签名不会算错,剩下的只有密钥不对
  3. 如果坚持自行签名:签名串是三行 timestamp\nnonce\n请求体原文,HMAC-SHA256,hex 小写

调接口报 40002(时间戳超窗或重放)

  1. 服务器时钟不准是主因:与标准时间差超过 5 分钟就会被拒。date 看一眼,配置 NTP 校时
  2. 如果是重放同一请求:正常,换个请求即可(SDK 每次自动生成新 nonce,不会触发)

调接口报 40003(商户不存在或已禁用)

merchant_id 拼写、环境(联调商户号在生产环境不存在)。都对就联系顽兔确认商户状态。

收不到 webhook 回调

按顺序排查,多数卡在第 1、2 步:

  1. 先查单pay.query_order(...) 看状态。不是 paid 说明支付本身没完成,和回调无关
  2. 回调地址公网可达吗:本地开发必须用内网穿透,穿透地址变了要同步给顽兔更新配置
  3. 路径对吗:配置的完整地址要和你的路由完全一致(含 /wantu/webhook 这段)
  4. 返回 2xx 了吗:网关只认 HTTP 状态码。返回 4xx/5xx 或超过 10 秒不响应都会进入重试
  5. 回调会按 1 分钟到 12 小时的间隔自动重试 8 次,修好配置后等下一轮即可,不会丢

verify_webhook 抛 WantuWebhookVerifyError

  1. 九成是 rawBody 问题:验签必须用请求体原文。FastAPI 用 await request.body(); 如果挂了全局中间件提前读过 body,或先调了 request.json(),签名必然对不上
  2. 配置了独立 webhook_secret 但代码没传(或反过来):两边要一致
  3. 服务器时钟不准(同 40002)

订单一直是 created

用户没有完成支付(没扫码、扫了没付、付到一半关页面)。这不是故障:

  • 查单接口会向渠道兜底确认,真付了状态会自己变成 paid
  • 超时(默认 15 分钟)后订单自动变 closed,引导用户重新下单即可

支付页打不开 / 500 / 提示系统繁忙

联调环境对接的是支付宝沙箱,沙箱偶发不稳定属于常态:等几分钟重试,订单超时了就重新 下一单。生产环境出现同样现象请立即反馈顽兔。

银联商务聚合码:iframe 白屏 / pay_url 浏览器打不开

都不是故障,是用法问题:channel: "chinaums"pay_url二维码内容,不是网页——

  1. 不能放 iframe,要用二维码库渲染成码图(见发起支付的银商一节)
  2. 电脑浏览器直接打开会提示不支持:该地址只能在微信、支付宝、云闪付 App 内打开, 手机扫码图就是正常入口
  3. 下单报 50002「渠道未启用」:银商渠道还没在顽兔侧开通,先按默认支付宝接入

担心重复入账

回调一定会重复送达(重试机制决定的),防线是入账 SQL 的条件更新:

UPDATE orders SET status = 'paid' WHERE out_trade_no = %s AND status = 'created';
-- 更新行数为 1 才加积分;为 0 说明已处理过,直接返回 200

自查是否发生过重复入账:按 out_trade_no 分组数积分流水,大于 1 行才有问题。

金额报错(40004 或 SDK 本地拦截)

金额必须是字符串、单位元、最多两位小数:"100.00" 对,100"1.234" 错。 SDK 会在本地直接拦下不合法金额,报错信息里写了原因。