PC网页支付宝支付成功但未收到回调
结论
支付成功但系统没有收到回调,通常不代表交易失败。更常见的情况是支付宝异步通知没有送达 notify_url,或者通知已经到达,却被网关、验签逻辑或业务代码拦截。
交易号 2021082622001426621423547493 只能用来定位交易,无法单凭交易号确定原因。应先调用 alipay.trade.query 确认交易状态,再查看支付宝通知记录、服务器访问日志和回调处理日志。确认支付成功后,即使异步通知丢失,也可以通过主动查询补单。
常见原因
notify_url 无法被支付宝访问
notify_url 必须是支付宝服务器能够直接访问的公网地址。以下情况可能导致通知失败:
- 使用了
localhost、内网 IP 或只能从公司网络访问的域名。 - 域名解析错误,或者 HTTPS 证书无效。
- 防火墙、安全组、WAF、CDN 或反向代理拦截了请求。
- 回调地址触发登录跳转、HTTP 重定向或鉴权拦截。
- 创建支付请求时没有正确传递
notify_url。
先查看 Web 服务器访问日志,确认是否收到支付宝发来的 POST 请求。不要只检查应用业务日志,因为请求可能根本没有进入应用。
混淆同步跳转和异步通知
return_url 是用户完成支付后,浏览器跳转到的地址。如果用户关闭页面或网络中断,跳转可能不会发生。
notify_url 才是支付宝服务器发送异步支付结果的地址。业务系统应以异步通知或主动查询结果为准,不能根据浏览器跳转直接认定支付成功。
回调到达后验签失败
支付宝异步通知通常以 application/x-www-form-urlencoded 方式提交。验签失败常见于以下情况:
- 使用 JSON 读取请求体,造成通知参数丢失。
- 验签时遗漏参数,或者修改了参数值。
- 配置了错误的支付宝公钥。
- 混淆了“支付宝公钥”和“应用公钥”。
charset、sign_type与实际配置不一致。- 验签前对参数做了二次 URL 解码或字符集转换。
- 混用了沙箱环境和正式环境的密钥或网关配置。
验签时应使用支付宝发送的完整原始参数集合,并交给支付宝 SDK 处理,不要自行拼接待签名字符串。
业务处理异常,但日志看起来像“没有回调”
通知可能已经进入应用,却在后续处理环节失败,例如:
- 数据库连接或事务异常。
- 根据
out_trade_no找不到本地订单。 - 订单金额或商户身份校验不通过。
- 重复通知引发唯一键冲突。
- 回调接口响应超时。
- 处理成功后没有返回纯文本
success。
如果支付宝没有收到符合要求的成功响应,通常会按照通知机制重试。因此,还应检查同一订单是否收到过多次通知。
排查步骤
1. 主动查询交易状态
使用 alipay.trade.query 查询交易号:
{
"trade_no": "2021082622001426621423547493"
}
也可以使用商户订单号 out_trade_no 查询。根据接口响应中的 trade_status 判断交易状态。常见的支付成功状态包括:
TRADE_SUCCESSTRADE_FINISHED
如果查询结果不是成功状态,不应执行支付成功补单。具体响应字段以当前接入的支付宝开放平台文档和 SDK 定义为准。
2. 核对支付请求中的回调地址
检查创建支付请求时实际提交的 notify_url,不要只看配置文件。多环境部署时,正式环境仍在使用测试地址是常见问题。
Java SDK 的调用形式通常类似:
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setReturnUrl("https://www.example.com/alipay/return");
request.setNotifyUrl("https://www.example.com/alipay/notify");
request.setBizContent(bizContent);
AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
确保 notify_url:
- 可以从公网访问;
- 接受
POST请求; - 不要求用户登录;
- 不依赖浏览器 Cookie;
- 不经过验证码或人机校验;
- 不会被 CSRF 校验直接拒绝。
3. 按链路逐层检查日志
按照请求经过的链路依次检查:
- DNS、CDN 或负载均衡访问日志;
- Nginx、Apache 等 Web 服务器访问日志;
- API 网关、WAF 和安全防护日志;
- 应用入口日志;
- 验签日志;
- 订单更新和数据库事务日志;
- 接口最终返回的内容及耗时。
如果 Web 服务器完全没有请求记录,应重点检查公网可达性和安全策略。如果服务器有请求记录,但应用没有记录,则应检查代理转发、路由、请求方法和应用异常。
4. 正确处理并验证通知
下面是 Java Servlet 风格的示例。具体类名和配置方式取决于所使用的支付宝 SDK 版本:
@PostMapping("/alipay/notify")
@ResponseBody
public String notify(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (Map.Entry<String, String[]> entry : requestParams.entrySet()) {
params.put(entry.getKey(), String.join(",", entry.getValue()));
}
try {
boolean verified = AlipaySignature.rsaCheckV1(
params,
alipayPublicKey,
"UTF-8",
"RSA2"
);
if (!verified) {
return "failure";
}
String tradeStatus = params.get("trade_status");
String tradeNo = params.get("trade_no");
String outTradeNo = params.get("out_trade_no");
String totalAmount = params.get("total_amount");
String appId = params.get("app_id");
String sellerId = params.get("seller_id");
// 校验 app_id、seller_id、订单号和订单金额。
// 只有全部匹配时才能更新订单。
validateNotification(
appId,
sellerId,
outTradeNo,
totalAmount
);
if ("TRADE_SUCCESS".equals(tradeStatus)
|| "TRADE_FINISHED".equals(tradeStatus)) {
markOrderPaidIdempotently(outTradeNo, tradeNo);
}
return "success";
} catch (Exception e) {
// 记录异常,但不要在日志中输出私钥等敏感配置。
return "failure";
}
}
验签通过后,不能立即更新订单。还应至少校验以下内容:
app_id是否属于当前应用;seller_id是否为预期收款账号;out_trade_no是否对应本地订单;total_amount是否与本地订单金额一致;trade_status是否表示支付成功;- 该支付宝交易号是否已经绑定到其他订单。
处理成功后应返回纯文本:
success
不要返回 JSON、HTML 页面或包含额外说明的字符串。
5. 做好幂等和补单
异步通知可能重复发送,因此订单更新必须具备幂等性。例如,只允许未支付订单第一次变更为已支付:
UPDATE payment_order
SET status = 'PAID',
trade_no = :tradeNo,
paid_at = CURRENT_TIMESTAMP
WHERE out_trade_no = :outTradeNo
AND status = 'PENDING';
如果受影响行数为 0,应继续判断订单是否已经处理成功,不能直接认定回调失败。
对于已经确认支付成功,但异步通知始终无法正常处理的订单,可以通过人工或自动方式补单:
- 调用
alipay.trade.query; - 校验商户订单号、交易金额和收款方信息;
- 在数据库事务中幂等更新订单;
- 记录补单来源、交易号和查询响应摘要;
- 修复
notify_url或回调处理问题,防止后续订单再次漏单。
注意事项
- 不要仅凭用户截图、前端提示或
return_url参数更新订单。 - 不要通过关闭验签临时解决问题。
- 不要将应用私钥或支付宝公钥全文写入日志。
- 回调接口应尽快完成必要处理并返回结果。耗时任务可以在订单状态写入数据库后异步执行。
- 比较金额时建议使用十进制定点类型,例如 Java 的
BigDecimal,不要使用double。 - 生产环境和沙箱环境必须分别配置网关、应用标识及密钥。
- 交易号属于支付业务数据。对外排查时应做好脱敏,并通过商户后台或开放平台工单提交给有权限的支持人员。
备注:内容仅供参考。
