PAYATHON 2026

APP调起支付宝沙箱支付后输入密码提示支付失败

支付小周

结论

APP 调起支付宝沙箱收银台后,如果输入支付密码才出现“支付失败”,问题通常不在 APP 的调起动作,而是支付宝在创建或提交交易时拒绝了订单。

可以先检查以下内容:

  1. APP、服务端和支付宝客户端是否都在使用沙箱环境。
  2. 当前登录的是沙箱买家账号,还是正式支付宝账号。
  3. app_id、应用私钥和支付宝公钥是否属于同一个沙箱应用。
  4. 服务端生成的 orderStr 是否签名正确、参数完整。
  5. 支付结果中的 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());

正确的支付结果处理方式

支付流程可以按以下方式处理:

  1. APP 向商户服务端申请支付订单。
  2. 服务端生成并签名 orderStr。
  3. APP 将 orderStr 原样传给支付宝 SDK。
  4. APP 根据返回状态显示“支付处理中”或“支付未完成”。
  5. 服务端验证支付宝异步通知的签名。
  6. 服务端核对 app_id、out_trade_no、total_amount 和收款方信息。
  7. 必要时调用 alipay.trade.query 查询最终状态。
  8. 确认交易状态成功后,再更新业务订单。

客户端支付回调不能作为唯一依据。没有收到 notify_url 通知也不代表支付失败,因为异步通知可能因网络原因延迟或重试。

注意事项

  • 不要把商户私钥打包进 APP。
  • 不要在生产日志中记录完整支付密码、私钥或用户敏感信息。
  • 沙箱应用和正式应用应分别维护配置,避免通过手工复制临时切换。
  • APP 发起支付前,先确认服务端已经成功生成订单。
  • 调试阶段保留完整错误码,对用户则显示易于理解的提示。
  • 修改密钥或应用公钥后,确认平台配置已经生效,并同步更新服务端配置。
  • 如果完整返回值中只有 resultStatus=4000,没有可用的 sub_code 和 sub_msg,还需要检查服务端 SDK 响应、支付宝开放平台调用记录和交易查询结果。

遇到这类问题时,不要反复修改支付密码。先取得完整支付结果,再检查沙箱账号、运行环境、应用配置、签名和订单参数。通常可以根据 sub_code、sub_msg 或交易查询结果找到具体原因。

备注:内容仅供参考。