微信支付 V3 对接踩坑记录:从签名失败到「已付款仍显示未支付」

我们在企业评估系统上完整跑通了微信支付 V3 的真实收费闭环,中间踩的坑一个不落。这篇把原因和改法都写清楚了,能帮你少熬两个通宵。

幕僚产品团队··约 8 分钟

微信支付 V3 的文档是完整的,但它把最容易错的几件事分散在四五个页面里。我们把真实踩过的坑按「症状 → 原因 → 改法」记下来。

一、签名失败:先分清三把「钥匙」

V3 里同时存在三个容易混的东西,签错任何一个都是签名失败:

名称作用常见错法
APIv3 密钥回调通知做解密/验签把它当私钥去签名请求
商户 API 私钥(.pem)你的请求签名和上面那个搞混
平台证书微信返回的签名不下载、不更新,硬编码在代码里

改法:请求签名只用商户私钥;回调验签只用平台证书。平台证书要能自动下载并按需轮换,不要把一个证书序列号写死在代码里——证书是会过期的。

二、签名串格式:一个字符都不能差

V3 的签名串是五行拼接:

HTTP方法\n
URL路径(含 query,不含域名)\n
时间戳\n
随机串\n
请求体原始字符串\n

踩过的三个细节:

  • URL 必须带 query,且只能是路径部分。拼成完整 URL(带 https://)必失败。
  • 请求体要用原始字节串。如果你先把 JSON 反序列化再序列化,键顺序和空格变了,签名就对不上——签名的串和发出去的串必须是同一个。最稳的做法是先序列化成字符串,用这个字符串同时去签名和发送。
  • 每次都要重新生成时间戳和随机串,不要复用。

三、回调不生效:域名、重试、幂等三件事

1. 回调地址必须公网可达的 HTTPS,且不能重定向。内网地址、HTTP、301/302 跳转,微信都不会跟。

2. 回调必须返回 200。这是最容易踩的一条:如果业务代码在回调里抛异常、或者返回了非 200,微信会认为通知失败并按策略反复重试。结果就是同一条支付通知被处理多次。

正确做法是先验签 → 落库标记录 → 立刻返回 200 → 异步去做后续业务逻辑。不要把重业务塞在回调的同步链路里。

3. 业务必须幂等。用「商户订单号」做唯一键,重复通知直接返回成功、不重复发货。这是我们踩过的最贵的一个坑,下面单独说。

四、最贵的那个坑:「已付款,但订单还显示未支付」

这是我们真实遇到、也是最花时间定位的一个问题。用户在微信里明明付了钱,回到我们系统订单状态还是「待支付」。

根因:回调处理链路里,业务逻辑(更新订单状态、写日志、发通知)和返回 200 是同一个事务/同一段同步代码。中间任何一步抛错,整个请求就返回了非 200,微信判定通知失败并重试;而重试时业务代码又因为「已经部分写入」等原因提前 return,导致状态永远停在中间态。

改法:把回调拆成两步,中间用数据库状态做锚点。

  1. 同步阶段(必须在 200 之前完成,且要极短):验签 → 解密通知 → 用「商户订单号 + 通知 ID」写入一张通知流水表(带唯一索引)→ 返回 200。
  2. 异步阶段:由定时任务或队列消费流水表,去做真正的业务(改订单状态、发货、通知)。失败有重试,且天然幂等。
  3. 兜底主动查单:再加一个定时任务,扫「超过 N 分钟仍是待支付」的订单,主动调查询订单接口核对真实状态。这一步能救掉所有因网络或部署窗口期丢掉的通知——回调是不可靠的,主动查单才是最终事实来源

加上第 3 步之后,这个问题在我们线上再没复现过。

五、几个小但会卡住人的点

  • 金额单位是「分」。前端传元、后端传分,是经典的差 100 倍 bug。
  • 旧证书和新证书并存时,序列号要用当前生效的那本。我们在项目里同时持有 2022 与 2024 两套商户证书,切换时最容易出错的地方就是序列号还指向旧证书。
  • 配置文件的行尾符会咬人。密钥从环境变量或配置文件读取时,如果文件是 Windows 行尾(CRLF),读出来的字符串尾部可能带不可见的 \r,签名必失败。排查时先把读到的密钥打印长度核对,一眼就能发现多出来的字符。
  • 沙箱和正式环境的密钥不通用,上线前确认所有配置都切到了正式环境。

一句话总结

V3 的难点不在密码学,在顺序和边界:什么时候验签、什么时候返回 200、什么该同步做、什么必须异步做、事实以谁为准。把这几个边界划清楚,它就没有想象中那么难。

回调和主动查单都要有,且要有通知流水表 —— 这三样齐了,支付才算真的跑通。

这篇说的问题,你正在遇到?

可以直接聊聊 —— 先做一次需求梳理,比自己猜要快。

hi@muliao.studio工作日 10:00 - 19:00成都

微信二维码待补充

先加微信号:muliao-studio

留个联系方式

写上怎么称呼你、怎么联系你,就够了。

任意一种都行,我们按你给的方式联系
我们只用它联系你,不会外传 · 24 小时内回复