支付宝沙箱退款返回系统异常,今天是否正在维护?
结论
仅凭这次返回结果,无法确认支付宝沙箱今天是否正在维护。
code="20000"、sub_code="aop.ACQ.SYSTEM_ERROR" 和 msg="Service Currently Unavailable" 表明支付宝侧服务暂时不可用或处理异常。原因可能是沙箱服务波动、网关内部异常或临时故障,但这不等于官方发布了维护通知。响应中也没有维护时间或预计恢复时间等信息。
目前退款结果并不明确,因此不要直接判定退款失败,也不要马上反复提交退款请求。应先查询交易和退款状态,再决定是否重试。
返回结果说明
关键字段如下:
{
"code": "20000",
"msg": "Service Currently Unavailable",
"sub_code": "aop.ACQ.SYSTEM_ERROR",
"sub_msg": "系统异常",
"refund_fee": "0.00",
"send_back_fee": "0.00"
}
这些字段的含义是:
10000通常表示接口业务处理成功。20000表示服务暂不可用,本次调用没有返回明确的成功结果。aop.ACQ.SYSTEM_ERROR是系统级异常,不属于“退款金额错误”或“交易不存在”这类明确的业务错误。refund_fee="0.00"不能单独作为退款失败的最终依据,仍应以退款查询结果和交易状态为准。
还要注意,请求中的 outTradeNo 是 030710482217413,而响应中的 out_trade_no 是 VP250227075320250307002。两者不一致,应优先排查以下问题:
- 实际发送给支付宝的
out_trade_no是否经过业务层转换; - 日志中的请求和响应是否来自同一次调用;
- SDK 请求对象是否被复用;
- 是否通过
trade_no定位交易,但日志仍打印了另一个本地订单号; - 中间服务是否重新组装或覆盖了退款参数。
建议处理步骤
1. 查询原交易状态
先调用 alipay.trade.query,并使用支付宝交易号:
{
"trade_no": "2025030722001472610505209996"
}
确认交易是否存在,以及当前是否仍可退款。同时核对查询结果中的 out_trade_no,判断它对应的是哪个本地订单。
2. 查询退款结果
如果退款请求设置了 out_request_no,调用 alipay.trade.fastpay.refund.query:
{
"trade_no": "2025030722001472610505209996",
"out_request_no": "唯一退款请求号"
}
out_request_no 应由商户系统生成,并在同一次退款的查询和重试过程中保持不变。如果每次重试都随机生成新的值,支付宝可能会将其识别为新的退款请求。
如果原调用没有保存 out_request_no,需要结合交易查询结果、商户退款记录和支付宝沙箱账单判断实际状态。
3. 核对沙箱环境配置
检查请求是否混用了正式环境和沙箱环境的数据:
- 网关地址应指向支付宝沙箱网关;
app_id应属于对应的沙箱应用;- 应使用沙箱应用密钥和支付宝沙箱公钥;
trade_no必须由同一沙箱环境中的交易生成;- 沙箱买家账号、卖家账号和应用应属于同一套沙箱配置。
正式环境生成的 trade_no 不能直接用于沙箱退款,沙箱环境生成的 trade_no 也不能用于正式环境退款。
4. 确认未退款后再有限重试
查询并确认退款没有成功后,可以对系统异常进行延迟重试,例如等待数秒后再次调用,并采用指数退避策略。不要在短时间内无限循环调用。
重试时应保持以下信息不变:
- 原交易标识;
- 退款金额;
out_request_no;- 退款业务含义。
Java 示例
下面是一种“先发起退款,结果不明确时再查询”的处理方式。支付宝 Java SDK 不同版本的类名可能略有差异,请以项目当前使用的 SDK 为准。
String tradeNo = "2025030722001472610505209996";
String refundRequestNo = "REFUND_030710482217413_001";
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
request.setBizContent("""
{
"trade_no": "%s",
"refund_amount": "10.00",
"refund_reason": "正常退款",
"out_request_no": "%s"
}
""".formatted(tradeNo, refundRequestNo));
AlipayTradeRefundResponse response = alipayClient.execute(request);
if ("10000".equals(response.getCode())) {
// 退款成功,保存支付宝返回结果
} else if ("20000".equals(response.getCode())
|| "aop.ACQ.SYSTEM_ERROR".equals(response.getSubCode())) {
// 结果不明确,不要立即认定退款失败
// 稍后调用退款查询接口确认
} else {
// 明确的业务失败,根据 sub_code 和 sub_msg 处理
}
退款查询示例:
AlipayTradeFastpayRefundQueryRequest queryRequest =
new AlipayTradeFastpayRefundQueryRequest();
queryRequest.setBizContent("""
{
"trade_no": "%s",
"out_request_no": "%s"
}
""".formatted(tradeNo, refundRequestNo));
AlipayTradeFastpayRefundQueryResponse queryResponse =
alipayClient.execute(queryRequest);
if ("10000".equals(queryResponse.getCode())) {
// 根据查询结果更新本地退款状态
} else {
// 记录 code、sub_code、msg、sub_msg,等待后续查询或人工核查
}
如何确认是否正在维护
要确认沙箱是否正在维护,应以支付宝开放平台公告、沙箱控制台提示或支付宝技术支持的答复为准。当前响应只能说明调用时发生了系统级异常,无法证明当时存在计划维护。
提交问题时,可以提供以下信息,但不要公开应用私钥、完整签名原文或用户敏感数据:
- 沙箱
app_id; - API 名称
alipay.trade.refund; - 请求发生的准确时间和时区;
trade_no、实际发送的out_trade_no;out_request_no;- 返回的
code、sub_code、msg和sub_msg; - 支付宝返回的请求标识或网关链路标识(如果 SDK 日志中存在)。
注意事项
- 遇到系统异常时,应遵循“先查询、后重试”的原则,避免重复退款。
- 金额建议使用带两位小数的字符串,例如
"10.00"。 - HTTP 请求成功或验签成功不代表退款成功,最终仍需检查业务响应码。
- 当前请求与响应中的
out_trade_no不一致,这个问题比“是否维护”更应该优先排查。 - 示例中的交易日期看起来属于历史数据。如果是在较晚时间重新测试,还需要确认沙箱交易是否仍然存在、是否已经退款,以及沙箱数据是否被重置。
备注:内容仅供参考。
