我的博客

支付回调为什么总是收不到?一份排查清单

接入支付时最让人头疼的问题之一:用户明明付款成功了,服务器却迟迟收不到回调,订单一直停在"待支付"。

下面以支付宝为例,按照从外到内的顺序列出常见原因。微信支付的情况大同小异。

一、请求里有没有带 notify_url

先确认下单时确实传了 notify_url,并且是完整的绝对地址。可以把生成的支付表单打印出来检查一下。

开放平台里配置的"应用网关"和"授权回调地址"都不是支付结果的通知地址,只配置了它们是收不到支付通知的。

二、地址能不能从公网访问

  • localhost、内网 IP 肯定收不到,本地调试要用内网穿透;
  • 找一台外网机器,或用手机流量执行 curl -X POST https://你的域名/pay/notify,确认能连通;
  • 云服务器的安全组、系统防火墙是否放行了 80/443;
  • 有没有开启 WAF 或防火墙的"境外 IP 拦截""频率限制"等规则,误拦了支付宝的服务器。

三、HTTPS 是否正常

  • 证书是否过期;
  • 证书链是否完整:浏览器会自动补全缺失的中间证书,但服务器之间的请求不会。可以用 openssl s_client -connect 你的域名:443 -showcerts 检查;
  • 建议使用标准的 443 端口。

四、有没有发生跳转

  • 很多站点会把 HTTP 301 到 HTTPS,或者把不带 www 的域名跳到带 www 的。不要指望回调请求会跟随跳转,notify_url 直接写最终地址;
  • 地址末尾的斜杠也可能触发跳转,注意和路由保持一致。

五、请求有没有被中间件拦截

这是最常见的原因:

  • 登录校验:回调接口不能要求登录;
  • CSRF 校验:支付宝的请求没有你的 CSRF Token,会被直接拒绝,回调路由要排除在外;
  • 请求体解析:支付宝发送的是 application/x-www-form-urlencoded 格式,只配置了 JSON 解析的话,拿到的 body 是空的;
  • 后端框架的路由前缀:确认 notify_url 的路径和实际路由完全一致。

六、收到了但处理失败

查看服务器日志,确认请求是否已经到达:

grep "/pay/notify" /var/log/nginx/access.log | tail

如果 Nginx 日志里有请求,说明网络没问题,问题在代码:

  • 验签失败:检查代码里用的是不是"支付宝公钥",而不是"应用公钥";沙箱和正式环境的公钥也不一样;
  • 返回值不对:必须返回纯文本 success,不能是 JSON、不能有 HTML 包裹、不能多出空格或换行;
  • 处理过程中抛异常:比如订单号查不到、金额比对时类型不一致(字符串 "9.9" 和 "9.90")。

七、兜底:主动查单

无论回调多可靠,都应该有主动查询作为兜底:

  • 用户支付完成跳回页面时,主动调用一次 alipay.trade.query;
  • 页面上提供"我已支付,刷新"按钮;
  • 定时任务扫描最近一段时间内仍为待支付的订单,逐个查询。

这样即使回调出了问题,用户也不会白白付钱拿不到东西。