支付回调系统必须严格满足验签、解密、幂等、响应格式四重校验;微信v3回调需用平台证书解密aes-gcm加密的json,支付宝需手动拼参验签,均须redis幂等+jwt上下文校验,响应仅允许纯“success”字符串。

支付回调系统不是“收到通知就更新订单”,而是必须同时满足验签、解密、幂等、响应格式四重校验,缺一不可;用 http.HandleFunc 直接写回调函数几乎必然出问题。
微信支付 v3 回调必须用 raw XML + 平台证书解密
微信 v3 的回调是加密的 JSON(不是 XML),但很多人还按老文档处理 XML,导致解密失败或验签不通过。
- 原始请求 body 是 AES-GCM 加密的 JSON 字符串,
r.Body必须一次性读完:body, _ := io.ReadAll(r.Body),不能用r.FormValue或json.NewDecoder(r.Body) - 解密必须用平台证书中的公钥(不是商户私钥)+
resource.ciphertext+resource.nonce+resource.associated_data,推荐直接用wechatpay-go.DecryptNotification - 解密后得到明文 JSON,再从中提取
resource.sign和resource.algorithm进行验签;漏掉这步等于白解密 - 响应体只能是纯字符串
"success",且不能带任何 HTTP header 之外的输出(日志、中间件fmt.Println都会导致重试)
支付宝回调验签前必须手动拼参,不能用 url.Values.Encode()
支付宝签名要求对所有非 sign / sign_type 参数按 key 升序拼接,值不做 URL decode —— 而 Go 的 url.Values.Encode() 会自动 encode,结果必然验签失败。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 正确做法:用
r.Form获取全部参数 → 转成map[string][]string→ 过滤掉"sign"和"sign_type"→ 对 key 排序 → 拼成key1=value1&key2=value2格式 - 签名算法取决于
sign_type:常见为RSA2(对应 SHA256withRSA),需用crypto/rsa+crypto/sha256手动验签,不能依赖 SDK 黑盒逻辑 - 验签用的公钥是支付宝平台提供的 RSA 公钥(PEM 格式),不是你自己的私钥,也不能用 base64 解码后再加载
- 同步回调(
return_url)和异步回调(notify_url)都需验签,但异步回调必须返回"success"字符串,否则持续重试
回调接口必须自带幂等控制,Redis 是最轻量可靠的选择
微信/支付宝都会在异常时重发回调,没有幂等机制会导致重复发货、重复扣款、状态错乱等生产事故。
- 不要只靠
out_trade_no做唯一索引——它可能被恶意复用或平台误发,应以回调携带的notify_id(微信)或trade_no+timestamp(支付宝)组合做 Redis SETNX 键 - 键过期时间建议设为 24 小时(微信回调最大重试间隔约 24h),避免因网络抖动导致永久锁死
- 幂等判断必须在验签之后、业务处理之前完成;验签失败也应记录日志,但不写入幂等键(防止攻击者刷键)
- 不要用数据库唯一约束替代幂等——高并发下主键冲突会抛异常,不如 Redis 原子操作干净
JWT 用于回调上下文关联,但绝不能替代平台验签
JWT 只解决“这个回调是不是来自我自己的某次下单请求”,不解决“这个回调是不是微信/支付宝发的”。两者职责完全不同,混用等于裸奔。
- 用户下单时生成 JWT,载荷含
order_id、amount、exp(建议 15 分钟),签名密钥与支付平台无关 - 前端唤起 SDK 前,把 JWT 放入
passback_params(支付宝)或scene_info(微信),确保回调原样带回 - 回调入口先验平台签名 → 再解析 JWT → 校验
exp和order_id是否匹配本次out_trade_no→ 不匹配则拒绝处理 - JWT 签名算法推荐
HS256(简单)或RS256(更安全),但密钥必须和业务登录态隔离,不能复用
最易被忽略的是响应体控制:哪怕验签、解密、幂等、JWT 全部通过,只要 fmt.Fprint(w, "success") 前有任意一行日志输出或中间件写了 header,微信就会判定失败并重试。这不是 bug,是设计契约。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










