案例 微信支付 V3 切公钥模式:报「无可用的平台证书」时,先查 Wechatpay-Serial 和证书链

2026-09-12 21:02:58

微信支付 V3 切公钥模式:报「无可用的平台证书」时,先查 Wechatpay-Serial 和证书链

背景:新商户号为什么报平台证书不可用

微信支付 V3 目前推荐使用微信支付公钥取代原来的平台证书。如果代码里配置的是平台证书模式,新申请商户号可能遇到报错:

无可用的平台证书,请在商户平台-API安全申请使用微信支付公钥

解决办法是去商户平台「API 安全」申请微信支付公钥,然后把代码里的证书加载逻辑换成公钥模式。

新商户号默认使用公钥模式,而不是平台证书模式。但老 SDK 还按平台证书规范加载,就会报这个错。

回调验签失败先排查三点

  1. 用没用对微信支付公钥,不是商户 API 证书。
  2. 公钥有没有填成 APIv3 密钥。
  3. 验签用的 serial number 跟请求头里的 Wechatpay-Serial 是否一致。常见错误是把商户证书序列号拿去验微信平台签名。

API 请求返回 401 签名错误

排查四个维度:

  • 私钥是否匹配。
  • 证书序列号是否对应。
  • 请求体字符串与签名原文是否一致。
  • 时间戳是否偏差过大。

可以用官方签名工具与本地生成的签名结果对比。

平台证书轮换与 /v3/certificates

微信 V3 平台证书每 12 个月轮换。客户端要同时保留旧新两张,按 Wechatpay-Serial 头选证书。

SDK 要能自动拉新,每天一次。证书从 /v3/certificates 下载后,用 APIv3 密钥 AES-GCM 解密。

回调 HTTPS 证书链:浏览器能打开不代表微信能验通

浏览器能打开不代表微信支付服务端能验通,其 root store 更严格。用下面命令验证证书链:

openssl s_client -connect your.domain:443 -showcerts

缺中间证书的补上。证书过期要加 30 天预警。支付宝应用证书有效期 2–5 年,微信商户证书 5 年。

标识类坑:out_trade_no、AppID 与 openid

out_trade_no 冲突:同一 out_trade_no 重下会报重复订单,或返回老订单。规则是一旦支付失败要重下,必须换新 out_trade_no,老的走关单。

AppID 与 mch_id 未绑定报 APPID_MCHID_NOT_MATCH

openid 跨 AppID 不通。同一用户在公众号和小程序下 openid 不同,下单要用同一 AppID 对应的 openid。

异步通知乱序与查单时机

处理慢时,退款通知可能早于支付通知到达。用状态机 + FOR UPDATE

查单时机过早可能返回 ORDERNOTEXIST,至少等 5 秒再查。

上线前 checklist

  • 证书过期预警。
  • 回调域名证书链完整。
  • out_trade_no 幂等:DB 唯一索引 + Redis SET NX
  • 异步通知验签 + 防重放 + 幂等三件套。
  • 主动查单兜底定时任务。
  • 关单策略:超 15 分钟未支付。
  • T+1 自动下载对账单。
  • 真实小额全链路灰度:0.01 元下单退款分账。

工程坑点清单

  • out_trade_no 幂等不能只靠业务判断,要有 DB 唯一索引,并配合 Redis SET NX 做前置拦截。
  • 证书链要用 openssl s_client -connect your.domain:443 -showcerts 验完整,缺中间证书就补。
  • HTTP 客户端连接/读取超时要显式设置,不要默认无限等待;Redis 锁超时时间要覆盖业务处理耗时,否则锁失效后并发会进来。
  • 查单至少等 5 秒,过早会 ORDERNOTEXIST

一个真实教训:Redis 锁超时释放,订单被更新两次

微信回调进来两三次,第一次处理时 Redis 锁超时释放,第二次线程进来发现订单还是待支付,又执行了一遍更新。

只用了 Redis 锁,没有数据库层唯一约束,两个线程在锁失效间隙同时更新订单表,第二次覆盖第一次。后来加 DB 唯一约束才堵住。

复制全文 生成海报 微信支付 支付对接 证书

推荐文章

程序员茄子在线接单