PAYATHON 2026

支付宝 App 支付提示订单参数异常,如何获取详细错误信息?

支付老李

结论

“订单参数异常”是支付宝 App 端的汇总提示。排查时,先完整记录客户端支付回调中的 resultStatus、memo 和 result,再根据 app_id、out_trade_no 和请求时间到支付宝开放平台查询。

从这段 orderStr 来看,建议先检查 passback_params。该字段中包含完整的 ALIPAY_PUBLIC_KEY 和一段 JSON,解码后的内容很可能超过接口允许的长度。这里最好只传简短的业务标识,其他数据留在商户服务端。

获取客户端返回的详细信息

Android

不要只显示 SDK 弹出的提示,还要记录 PayTask.payV2() 返回的完整 Map:

Runnable payRunnable = () -> {
    PayTask alipay = new PayTask(activity);
    Map<String, String> result = alipay.payV2(orderStr, true);

    String resultStatus = result.get("resultStatus");
    String memo = result.get("memo");
    String rawResult = result.get("result");

    Log.i("Alipay", "resultStatus=" + resultStatus);
    Log.i("Alipay", "memo=" + memo);
    Log.i("Alipay", "result=" + rawResult);

    // 切回主线程更新界面
};

Thread payThread = new Thread(payRunnable);
payThread.start();

需要关注三个字段:

  • resultStatus:支付结果状态。
  • memo:SDK 返回的提示信息。
  • result:支付宝返回的原始业务结果,其中可能包含 code、sub_code、sub_msg 等字段。

常见的 resultStatus 有:

  • 9000:支付成功。
  • 8000:结果处理中。
  • 4000:支付失败。
  • 6001:用户取消。
  • 6002:网络连接异常。

这些状态不能代替服务端验签和订单查询。最终支付状态应以异步通知或 alipay.trade.query 的查询结果为准。

iOS

记录支付回调中的完整字典:

[[AlipaySDK defaultService] payOrder:orderStr
                           fromScheme:@"yourAppScheme"
                             callback:^(NSDictionary *resultDic) {
    NSLog(@"Alipay resultStatus: %@", resultDic[@"resultStatus"]);
    NSLog(@"Alipay memo: %@", resultDic[@"memo"]);
    NSLog(@"Alipay result: %@", resultDic[@"result"]);
    NSLog(@"Alipay full result: %@", resultDic);
}];

如果 result 中有 JSON 响应,继续查看其中的 code、sub_code 和 sub_msg,不要只记录界面上显示的“订单参数异常”。

服务端需要记录什么

生成 orderStr 时,建议记录这些内容:

app_id
method
timestamp
sign_type
out_trade_no
biz_content 原始 JSON
待签名字符串
SDK 返回或异常堆栈

日志中的签名、用户信息和业务参数需要脱敏。应用私钥、访问令牌以及完整的个人信息不能写入日志。

还要注意,alipay.trade.app.pay 的服务端 SDK 通常只负责生成订单字符串并完成签名,这个阶段不一定会向支付宝提交请求。因此,成功生成 orderStr 并不表示支付宝已经校验了全部业务参数。有些详细错误只能从 App SDK 返回值或开放平台的请求排查功能中查到。

当前订单建议优先检查的参数

1. 精简 passback_params

当前参数解码后的结构大致如下:

{
  "user_id": "13636629851",
  "payment_discount": "0",
  "ALIPAY_PUBLIC_KEY": "MIIBIjANBgkqhkiG9w0BAQ...",
  "depot_uuid": "15e4d7c8-2e97-4258-bff3-96f6b07cd685"
}

这里有两个比较明显的问题:

  1. passback_params 内容太大。加入完整公钥后,很容易超过接口对该字段的长度限制。
  2. 回传参数不适合存放配置数据和完整的业务上下文,也没有必要传递 ALIPAY_PUBLIC_KEY。

更合适的做法是只传一个简短的业务标识:

{
  "biz_id": "abc123"
}

服务端再通过 out_trade_no 或 biz_id 查询实际的业务数据:

JSONObject bizContent = new JSONObject();
bizContent.put("subject", "pai");
bizContent.put("out_trade_no", outTradeNo);
bizContent.put("total_amount", "0.58");
bizContent.put("product_code", "QUICK_MSECURITY_PAY");
bizContent.put("timeout_express", "50m");
bizContent.put("passback_params", "biz_id=abc123");

AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
request.setBizContent(bizContent.toJSONString());
request.setNotifyUrl("https://example.com/alipay/notify");

AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
String orderStr = response.getBody();

passback_params 的具体长度和编码要求应以当前支付宝接口文档为准。不过,无论字段上限是多少,都不建议把完整的 RSA 公钥放进去。

2. 检查编码与签名顺序

orderStr 应由支付宝服务端 SDK 生成,不要手工拼接,也不要再次编码。

常见错误有:

  • 完成签名后又修改 biz_content。
  • 对整个 orderStr 再做一次 URL 编码。
  • 客户端先对字符串执行 URL 解码,再传给 PayTask。
  • 空格和加号被框架错误转换。
  • 签名使用的字符集与请求中的 charset 不一致。
  • 应用私钥与开放平台配置的应用公钥不匹配。
  • 使用支付宝公钥给订单签名。订单签名必须使用商户应用私钥。

客户端应直接使用服务端返回的原始字符串:

Map<String, String> result = new PayTask(activity).payV2(orderStr, true);

不要这样处理:

// 错误示例:可能破坏 sign、timestamp 等参数
String decoded = URLDecoder.decode(orderStr, "UTF-8");
Map<String, String> result = new PayTask(activity).payV2(decoded, true);

3. 检查时间戳

示例中的时间是:

2024-10-15 23:57:00

如果这只是历史日志,可以忽略。如果实际支付时还在重复使用这条 orderStr,就必须重新生成。订单字符串不应长期缓存和复用,timestamp、out_trade_no 及签名都要针对本次支付重新生成。

4. 检查通知地址

示例使用的是 HTTP:

http://charging.paitingche.cn/api/back

这不一定会直接导致“订单参数异常”,但生产环境建议换成公网可访问的 HTTPS 地址:

https://charging.paitingche.cn/api/back

通知接口不能依赖登录状态,也不能要求支付宝携带商户自定义 Cookie。收到通知后,服务端必须验签,并根据 out_trade_no 做幂等处理。

使用开放平台进一步定位

如果客户端只返回 resultStatus=4000 和内容笼统的 memo,可以到支付宝开放平台查看接口调用记录,或使用云排查及相关诊断功能。查询前准备好以下信息:

app_id
out_trade_no
请求发生的准确时间
alipay_sdk 版本
客户端平台和支付宝 App 版本
resultStatus
memo
完整 result(脱敏)

如果订单已经创建,还可以调用 alipay.trade.query:

AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent(
    "{\"out_trade_no\":\"" + outTradeNo + "\"}"
);

AlipayTradeQueryResponse response = alipayClient.execute(request);

System.out.println("code=" + response.getCode());
System.out.println("msg=" + response.getMsg());
System.out.println("subCode=" + response.getSubCode());
System.out.println("subMsg=" + response.getSubMsg());

如果查询结果显示交易不存在,请求可能在创建交易前就因参数、签名或编码问题被拒绝。这时应重点检查客户端的原始回调和开放平台诊断记录。

推荐排查顺序

  1. 完整记录 payV2() 返回的 resultStatus、memo 和 result。
  2. 删除 passback_params 中的 ALIPAY_PUBLIC_KEY,使用最小参数重新下单。
  3. 确认 orderStr 完全由官方 SDK 生成,客户端没有做任何额外处理。
  4. 核对应用私钥、应用公钥、支付宝公钥和 app_id,确认它们属于同一个应用及环境。
  5. 确认每次支付都使用新的时间戳和唯一的 out_trade_no。
  6. 在开放平台中,根据 app_id、订单号和请求时间查询诊断记录。
  7. 如果订单已经创建,再通过 alipay.trade.query 获取 sub_code 和 sub_msg。

就当前参数来看,应先精简 passback_params,然后重新生成并签名整个 orderStr。不能直接从现有字符串中删除字段后继续使用原签名,否则一定会验签失败。

备注:内容仅供参考。