沙箱支付成功后测试仍显示“等待用户完成支付”
结论
后台返回 {Status:1, Message:OK},只能说明商户系统认为支付处理成功,不能证明测试平台已经识别出这笔交易属于当前测试用例。
如果测试仍停留在【等待用户完成支付】,通常有两种情况:测试平台没有关联到这笔交易,或者支付接口虽然调用成功,但支付宝业务状态尚未达到最终成功状态。建议重点核对测试环境、应用身份、订单号、支付账号和 trade_status,再用全新的订单重新走一遍完整支付流程。
为什么后台成功,测试步骤却没有通过
测试平台与商户后台使用两套独立的状态判断机制:
- 商户后台通过同步跳转、异步通知或主动查询更新订单状态。
- 测试平台只认可在当前测试任务中,通过指定沙箱应用和沙箱账号完成的交易。
- 自定义返回值中的
Status:1和Message:OK不是支付宝标准交易状态,可能只表示接口请求成功,或商户程序执行成功。 - 判断交易是否完成,应以
alipay.trade.query返回的trade_status为准。
支付宝交易的最终业务状态通常应为:
TRADE_SUCCESS
或:
TRADE_FINISHED
如果只返回:
code=10000
msg=Success
通常只能说明接口调用成功,还需要继续检查 trade_status。
优先排查的项目
1. 确认使用的是同一个沙箱应用
创建支付订单和查询订单时,必须使用当前测试用例关联的沙箱应用,包括:
- 相同的沙箱
app_id - 相同的商户私钥
- 与该应用匹配的支付宝公钥或证书
- 沙箱网关
- 当前沙箱应用提供的买家账号
沙箱网关通常配置为:
https://openapi-sandbox.dl.alipaydev.com/gateway.do
如果支付发生在正式环境或另一个沙箱应用中,或者使用的账号不属于当前测试环境,那么即使交易成功,当前测试用例也可能无法识别。
2. 检查订单是否属于当前测试任务
不要使用历史订单号,也不要重复使用已经支付成功的 out_trade_no。每次重新测试时,都应生成一个全新的商户订单号,例如:
TEST_20240408161259_001
同时确认页面上实际支付的订单号与后台查询的订单号完全一致。本例需要核对:
out_trade_no = 202404087183014128443719680
trade_no = 2024040822001416970502542164
如果用户支付的是订单 A,后台查询的却是订单 B,后台可能仍然能查到一笔成功交易,但测试平台不会推进当前步骤。
3. 不要只判断自定义的 Status
下面的结果:
{Status:1 OutTradeNo:202404087183014128443719680 TradeNo:2024040822001416970502542164 Amount:9.90 Message:OK Subject:}
是业务系统封装后的结构,并非支付宝接口的完整原始响应。应记录并检查支付宝返回的这些字段:
code
sub_code
sub_msg
out_trade_no
trade_no
trade_status
total_amount
只有 trade_status 确认为 TRADE_SUCCESS 或 TRADE_FINISHED,才能认定支付宝侧的交易已经完成。
4. 在当前测试页面发起并完成支付
建议按以下顺序重新操作:
- 停止当前已卡住的测试。
- 重新启动测试用例。
- 从当前测试步骤生成新的支付链接。
- 使用指定的沙箱买家账号完成支付。
- 支付完成后,不要立即关闭浏览器、手机页面或中间跳转页。
- 等待页面完成
return_url跳转。 - 确认服务端已经收到
notify_url通知并完成验签。 - 使用相同的
out_trade_no调用交易查询接口。 - 返回测试平台,观察步骤是否推进。
如果支付链接来自历史日志、收藏夹或其他测试任务,应废弃该链接并重新创建订单。
交易查询判断示例
下面是 Go 风格的判断示例,字段名称需要根据实际使用的 SDK 调整:
resp, err := client.TradeQuery(outTradeNo)
if err != nil {
return fmt.Errorf("查询支付宝交易失败: %w", err)
}
if resp.Code != "10000" {
return fmt.Errorf(
"支付宝查询失败: code=%s sub_code=%s sub_msg=%s",
resp.Code,
resp.SubCode,
resp.SubMsg,
)
}
switch resp.TradeStatus {
case "TRADE_SUCCESS", "TRADE_FINISHED":
// 支付宝业务状态已确认成功
markOrderPaid(resp.OutTradeNo, resp.TradeNo, resp.TotalAmount)
case "WAIT_BUYER_PAY":
return fmt.Errorf("买家尚未完成支付")
case "TRADE_CLOSED":
return fmt.Errorf("交易已经关闭")
default:
return fmt.Errorf("未知交易状态: %s", resp.TradeStatus)
}
不要使用下面这种判断过于宽松的逻辑:
if resp.Code == "10000" {
markOrderPaid()
}
接口查询成功不代表交易已经支付成功。
异步通知也要正确处理
如果商户系统依赖 notify_url 更新订单,需要确保:
- 通知地址可以从公网访问。
- 使用支付宝公钥或证书完成验签。
- 校验通知中的
app_id、seller_id、out_trade_no和金额。 - 处理完成后,按接口要求返回成功响应。
- 同一通知重复到达时,订单处理应具备幂等性。
示意代码:
if !verifyAlipaySignature(params) {
return errors.New("支付宝通知验签失败")
}
if params["app_id"] != expectedAppID {
return errors.New("app_id 不匹配")
}
if params["out_trade_no"] != expectedOutTradeNo {
return errors.New("out_trade_no 不匹配")
}
if params["total_amount"] != expectedAmount {
return errors.New("支付金额不匹配")
}
tradeStatus := params["trade_status"]
if tradeStatus == "TRADE_SUCCESS" || tradeStatus == "TRADE_FINISHED" {
markOrderPaidIdempotently(params["out_trade_no"], params["trade_no"])
}
仍然卡住时怎么处理
如果已经确认以下条件全部满足:
- 使用当前测试用例对应的沙箱
app_id - 使用沙箱网关和指定的沙箱买家
- 使用全新的
out_trade_no - 支付发生在当前测试任务启动之后
alipay.trade.query明确返回TRADE_SUCCESS或TRADE_FINISHED- 页面正常完成跳转,异步通知也已通过验签并得到处理
- 测试任务仍在剩余时间内
但测试步骤仍长期显示【等待用户完成支付】,更可能是测试平台状态同步延迟,或当前测试任务出现异常。此时可以停止当前任务并重新创建一次测试。如果问题能够稳定复现,再向平台技术支持提交:
- 沙箱
app_id - 测试用例名称和执行时间
out_trade_notrade_no- 支付接口原始响应
- 查询接口原始响应
- 异步通知日志及验签结果
- 测试页面截图
提交材料时,可以隐藏私钥、签名原文和其他敏感凭据。不要只提供业务系统封装后的 {Status:1, Message:OK},因为这组信息不足以判断支付宝侧的交易状态,也无法说明测试平台为何没有完成关联。
备注:内容仅供参考。
