APP调起支付宝沙箱支付后输入密码提示支付失败
结论
APP 调起支付宝沙箱收银台后,如果输入支付密码才出现“支付失败”,问题通常不在 APP 的调起动作,而是支付宝在创建或提交交易时拒绝了订单。
可以先检查以下内容:
- APP、服务端和支付宝客户端是否都在使用沙箱环境。
- 当前登录的是沙箱买家账号,还是正式支付宝账号。
app_id、应用私钥和支付宝公钥是否属于同一个沙箱应用。- 服务端生成的
orderStr是否签名正确、参数完整。 - 支付结果中的
resultStatus、code、sub_code和sub_msg分别是什么。
界面上的“支付失败”不足以确定原因,应以支付宝返回的错误码和错误信息为准。
常见原因
1. 沙箱环境与正式环境混用
最常见的问题是环境配置没有完全对应,例如:
- 服务端使用沙箱
app_id,APP 调用的却是正式版支付宝客户端。 - 请求发往正式网关,使用的却是沙箱密钥。
app_id来自沙箱应用,私钥或支付宝公钥来自另一个应用。- APP 登录的是正式支付宝账号,订单却属于沙箱环境。
沙箱订单、沙箱账号和正式支付宝环境不能混用。应用信息、沙箱买家账号和测试方式都应从支付宝开放平台沙箱控制台获取。
2. 签名配置错误
APP 支付的订单字符串应由商户服务端签名。签名算法、字符集、密钥或待签名内容有误时,支付宝可能返回:
- 签名验证失败;
- 应用身份无效;
- 商户配置异常;
- 请求参数非法。
检查时需要确认:
sign_type与实际使用的签名算法一致,通常为RSA2;- 商户私钥与沙箱应用上传的应用公钥对应;
- 验签使用的是支付宝公钥,而不是应用公钥;
- 私钥中没有多余空格、换行或错误的 PEM 头尾;
app_id、密钥和网关属于同一套环境;- APP 没有自行拼接或修改服务端返回的
orderStr。
不要在 APP 中保存商户私钥或生成支付签名。这既有安全风险,也可能因客户端拼接的参数不一致而导致验签失败。
3. 订单参数不合法
调用 alipay.trade.app.pay 时,以下问题经常导致失败:
out_trade_no为空或被重复使用;total_amount格式错误;subject为空或长度不符合接口要求;product_code没有设置为QUICK_MSECURITY_PAY;- 订单已经关闭、过期或支付完成;
- 再次提交同一个商户订单号时,金额或商品信息发生了变化;
- 参数经过 URL 编码、JSON 转义或字符集转换后被破坏。
金额建议使用十进制字符串传递,例如 "0.01"。不要先用浮点数计算再直接转换,以免出现精度问题。
4. 沙箱买家账号或支付密码不正确
沙箱支付需要使用沙箱控制台提供的买家账号和对应的支付密码。注意区分:
- 登录密码:用于登录账号;
- 支付密码:用于确认付款。
使用正式账号、其他沙箱应用的测试账号,或者误把登录密码当作支付密码,都可能导致支付失败。
沙箱账号也可能出现状态异常、余额不足或测试数据被重置等情况。是否属于账号问题,需要结合收银台提示以及支付结果中的 sub_code、sub_msg 判断。
5. APP 支付客户端不支持当前沙箱测试方式
支付宝开放平台可能调整沙箱客户端的支持范围和安装方式。某些环境需要使用指定的沙箱钱包或测试入口,普通正式版支付宝客户端未必能完成沙箱订单。
这类信息会随平台调整,应以当前支付宝开放平台沙箱控制台的说明为准,不要只按照旧教程安装历史版本的沙箱客户端。
6. APP 没有完整解析支付结果
支付宝 SDK 返回的 resultStatus 只表示客户端层面的状态。常见值包括:
9000:订单支付成功;8000:正在处理中;4000:订单支付失败;5000:重复请求;6001:用户取消;6002:网络连接异常;6004:支付结果未知。
如果 APP 只显示“支付失败”,却没有记录 result 和 memo,真正的错误原因也会随之丢失。
即使客户端返回 9000,也不能直接把订单标记为最终支付成功。服务端仍需通过异步通知或主动查询确认交易状态。
排查步骤
第一步:记录完整的支付返回值
Android 调用示例:
PayTask payTask = new PayTask(activity);
Map<String, String> result = payTask.payV2(orderStr, true);
String resultStatus = result.get("resultStatus");
String resultData = result.get("result");
String memo = result.get("memo");
Log.d("Alipay", "resultStatus=" + resultStatus);
Log.d("Alipay", "result=" + resultData);
Log.d("Alipay", "memo=" + memo);
不要只记录 resultStatus。result 中通常还会包含业务响应,例如:
{
"alipay_trade_app_pay_response": {
"code": "40004",
"msg": "Business Failed",
"sub_code": "具体错误码",
"sub_msg": "具体错误原因"
}
}
具体字段内容取决于支付宝的实际返回结果。排查时先查看:
resultStatus
code
msg
sub_code
sub_msg
memo
第二步:检查三端环境是否一致
逐项确认:
- 服务端使用沙箱
app_id; - 服务端配置了该沙箱应用对应的商户私钥;
- 服务端配置了正确的支付宝公钥;
- SDK 请求使用沙箱网关;
- APP 使用当前沙箱要求的支付宝客户端或测试入口;
- APP 登录的是沙箱买家账号。
Java 服务端 SDK 的配置通常类似:
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi-sandbox.dl.alipaydev.com/gateway.do",
APP_ID,
MERCHANT_PRIVATE_KEY,
"json",
"UTF-8",
ALIPAY_PUBLIC_KEY,
"RSA2"
);
网关地址和 SDK 配置方式可能随平台调整,应以当前官方控制台和所用 SDK 文档为准。
第三步:检查服务端订单生成逻辑
Java 示例:
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
request.setNotifyUrl("https://example.com/alipay/notify");
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setOutTradeNo("ORDER_20260909_0001");
model.setTotalAmount("0.01");
model.setSubject("测试商品");
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
if (!response.isSuccess()) {
throw new IllegalStateException(
"生成支付宝订单失败: code=" + response.getCode()
+ ", subCode=" + response.getSubCode()
+ ", subMsg=" + response.getSubMsg()
);
}
String orderStr = response.getBody();
服务端应将 response.getBody() 原样返回给 APP。APP 不要再次修改、拆分、排序或重新编码订单字符串。
每次测试还应使用新的 out_trade_no。如果需要重试同一业务订单,应先查询原交易状态,不能修改金额后直接重复提交。
第四步:根据错误码定位问题
可以按照以下方向排查:
- 出现签名或应用相关错误时,检查
app_id、私钥、支付宝公钥和sign_type。 - 提示参数非法时,打印服务端提交的业务参数,检查必填项和字段格式。
- 买家账号异常时,改用沙箱控制台提供的有效买家账号。
- 订单重复或状态异常时,调用交易查询接口确认原订单状态。
- 返回
6002时,检查 APP 网络、代理、证书和设备时间。 - 返回
6001表示用户主动取消,不应当作系统故障处理。 - 返回
8000或6004时,不要立即判定失败,应由服务端查询最终交易状态。
主动查询示例:
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
AlipayTradeQueryModel model = new AlipayTradeQueryModel();
model.setOutTradeNo("ORDER_20260909_0001");
request.setBizModel(model);
AlipayTradeQueryResponse response = alipayClient.execute(request);
System.out.println("code=" + response.getCode());
System.out.println("subCode=" + response.getSubCode());
System.out.println("subMsg=" + response.getSubMsg());
System.out.println("tradeStatus=" + response.getTradeStatus());
正确的支付结果处理方式
支付流程可以按以下方式处理:
- APP 向商户服务端申请支付订单。
- 服务端生成并签名
orderStr。 - APP 将
orderStr原样传给支付宝 SDK。 - APP 根据返回状态显示“支付处理中”或“支付未完成”。
- 服务端验证支付宝异步通知的签名。
- 服务端核对
app_id、out_trade_no、total_amount和收款方信息。 - 必要时调用
alipay.trade.query查询最终状态。 - 确认交易状态成功后,再更新业务订单。
客户端支付回调不能作为唯一依据。没有收到 notify_url 通知也不代表支付失败,因为异步通知可能因网络原因延迟或重试。
注意事项
- 不要把商户私钥打包进 APP。
- 不要在生产日志中记录完整支付密码、私钥或用户敏感信息。
- 沙箱应用和正式应用应分别维护配置,避免通过手工复制临时切换。
- APP 发起支付前,先确认服务端已经成功生成订单。
- 调试阶段保留完整错误码,对用户则显示易于理解的提示。
- 修改密钥或应用公钥后,确认平台配置已经生效,并同步更新服务端配置。
- 如果完整返回值中只有
resultStatus=4000,没有可用的sub_code和sub_msg,还需要检查服务端 SDK 响应、支付宝开放平台调用记录和交易查询结果。
遇到这类问题时,不要反复修改支付密码。先取得完整支付结果,再检查沙箱账号、运行环境、应用配置、签名和订单参数。通常可以根据 sub_code、sub_msg 或交易查询结果找到具体原因。
备注:内容仅供参考。
