APP 唤起支付宝支付时提示交易订单处理失败
结论
“交易订单处理失败,请稍后重试”是支付宝客户端的通用提示,仅凭这句话无法判断具体原因。排查 alipay.trade.app.pay 时,先检查以下几项:
- 服务端签名所用的应用私钥,是否与当前
app_id配置的应用公钥配对,相关支付宝公钥或应用公钥证书是否配置正确。 - 服务端生成完整订单字符串后,APP 是否又对其进行了解码、拼接、排序或二次 URL 编码。
- 应用是否已经签约并开通 App 支付能力,调用环境、网关和密钥配置是否属于同一套环境。
out_trade_no是否重复,time_expire是否已经过期。- 手机与服务端的时间和时区是否正确。
示例请求中的 time_expire 是 2024-08-07 10:56:02。如果在这个时间之后发起支付,订单会因超时而失效。此时需要更换新的 out_trade_no,重新生成订单字符串。
先获取支付宝返回的详细结果
不要只记录客户端弹窗。APP 调用支付 SDK 后,应完整记录 resultStatus、memo 和 result,以便定位问题。
Android 示例:
PayTask alipay = new PayTask(activity);
Map<String, String> result = alipay.payV2(orderInfo, true);
String resultStatus = result.get("resultStatus");
String memo = result.get("memo");
String rawResult = result.get("result");
Log.d("Alipay", "resultStatus=" + resultStatus);
Log.d("Alipay", "memo=" + memo);
Log.d("Alipay", "result=" + rawResult);
常见状态如下:
9000:订单支付成功,但最终结果仍应以服务端异步通知或主动查询为准。8000:支付结果正在处理中。4000:订单支付失败。该状态涵盖的情况较多,还要结合memo、服务端日志和订单查询结果继续排查。6001:用户取消支付。6002:网络连接异常。
iOS 端也要记录 SDK 回调返回的完整结果字典,不能只根据客户端显示的提示判断原因。
检查订单字符串是否被修改
alipay.trade.app.pay 的正常调用流程如下:
服务端构造业务参数
→ 服务端使用应用私钥签名
→ 服务端返回完整 orderString
→ APP 将 orderString 原样传给支付宝 SDK
APP 收到订单字符串后,不应再进行这些处理:
- 对整个订单字符串再次执行
URLEncoder.encode。 - 先 URL Decode,再重新编码。
- 把字符串解析成 Map,然后重新排序或拼接。
- 修改
biz_content、timestamp、sign等字段。 - 把
+错误地转换为空格,或者破坏%2B、%2F、%3D。 - 使用 JSON 转义、HTML 转义等方式处理订单字符串。
请求中的 RSA2 签名含有 /、+、= 等特殊字符,经过 URL 编码后会变成 %2F、%2B、%3D。如果客户端、接口框架或中间网关再次解码或编码,支付宝验签就可能失败。
Android 端应把服务端返回的内容直接传给 SDK:
String orderInfo = response.body().getOrderString();
// 不要再次 URLEncoder.encode(orderInfo, "UTF-8")
PayTask alipay = new PayTask(activity);
Map<String, String> result = alipay.payV2(orderInfo, true);
可以分别记录服务端生成的值和 APP 收到的值,再逐字比较。记录日志时,应对 sign、订单号等敏感内容脱敏,不要公开保存完整的支付参数。
核对签名和应用配置
签名异常是这类问题的常见原因,需要逐项核对:
app_id是否属于当前商户和当前应用。- 使用的是否为该应用对应的应用私钥,而非支付宝公钥或其他应用的私钥。
- 开放平台中配置的应用公钥,是否与本地私钥配对。
- 是否混用了普通公钥模式和公钥证书模式。
sign_type是否为RSA2。- 签名字符集是否与请求中的
charset=UTF-8一致。 - 是否混用了沙箱应用、正式应用及其对应网关。
- 修改密钥后,服务端是否仍在读取旧配置或缓存。
使用普通公钥模式时,PHP SDK 的典型配置如下:
<?php
use Alipay\EasySDK\Kernel\Factory;
use Alipay\EasySDK\Kernel\Config;
$config = new Config();
$config->protocol = 'https';
$config->gatewayHost = 'openapi.alipay.com';
$config->signType = 'RSA2';
$config->appId = '实际应用的 app_id';
$config->merchantPrivateKey = '与应用公钥匹配的应用私钥';
$config->alipayPublicKey = '支付宝公钥';
Factory::setOptions($config);
不同 PHP SDK 使用的类名和配置字段可能不同,具体应以项目采用的 SDK 为准。“应用公钥""支付宝公钥”和”应用私钥”用途不同,不能互相替代。
由服务端统一生成订单参数
订单参数和签名必须由服务端生成,APP 内不能保存应用私钥。
使用传统 PHP SDK 时,可以采用类似下面的写法:
<?php
$aop = new AopClient();
$aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
$aop->appId = '实际应用的 app_id';
$aop->rsaPrivateKey = '应用私钥';
$aop->alipayrsaPublicKey = '支付宝公钥';
$aop->signType = 'RSA2';
$aop->postCharset = 'UTF-8';
$aop->format = 'json';
$request = new AlipayTradeAppPayRequest();
$bizContent = [
'out_trade_no' => 'ORDER_' . date('YmdHis') . random_int(100000, 999999),
'total_amount' => '0.01',
'subject' => '账户充值',
'time_expire' => date('Y-m-d H:i:s', time() + 1800),
];
$request->setBizContent(
json_encode($bizContent, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
);
$request->setNotifyUrl('https://example.com/alipay/notify');
$orderString = $aop->sdkExecute($request);
// 将 $orderString 原样返回给 APP
echo json_encode(
['order_string' => $orderString],
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);
notify_url 通常不是唤起支付的必填参数,但生产环境应配置一个可以公开访问的 HTTPS 地址,用于接收异步支付结果。
检查业务参数
示例中的基础参数没有明显缺失,不过以下内容仍需逐项检查。
out_trade_no
商户订单号在商户侧必须唯一。支付失败后如果需要重新创建交易,建议生成新的订单号,不要反复使用已经关闭、已经支付或参数与原交易不一致的订单号。
可以调用以下接口查询订单状态:
alipay.trade.query
如果订单已经关闭,或者交易内容与之前提交的内容不一致,应重新创建订单。
time_expire
time_expire 必须晚于订单创建时间,同时要保证服务端时钟和时区正确。示例设置了约 30 分钟的有效期,这种写法可以使用,但订单过期后,不能继续用原来的订单字符串发起支付。
建议明确设置服务器时区:
date_default_timezone_set('Asia/Shanghai');
$timeExpire = date('Y-m-d H:i:s', time() + 1800);
如果业务不需要主动限制支付时间,可以暂时移除 time_expire 进行对照测试,确认问题是否与订单有效期有关。
total_amount
0.01 的格式通常符合金额参数要求,但一分钱交易是否允许,还可能受产品能力、商户风控或具体业务场景限制。排查时可以改用正常测试金额,并检查支付宝商家平台或开放平台中是否有风险提示。
subject
subject 应如实描述商品或服务。示例中的”充值0.01赠5.00”包含充值和赠送含义,能否使用取决于实际签约产品、行业资质及业务场景。如果其他配置均无异常,可以暂时改成中性的真实交易描述进行对照测试,但不能通过虚假描述规避平台审核或风控。
检查产品权限和应用状态
还要在支付宝开放平台核对以下信息:
- 应用是否已经上线,而非仍处于未提交或审核状态。
- App 支付能力是否已经签约并处于可用状态。
- 签约商户与应用的绑定关系是否正确。
- 当前业务类目、商户资质和支付场景是否符合产品要求。
- 商户账户是否被冻结、限制收款或触发风险控制。
- 正式应用是否使用正式网关,沙箱应用是否使用沙箱环境。
如果同一套代码在沙箱中正常、在正式环境中失败,应重点比较 app_id、网关、应用私钥、支付宝公钥和产品签约状态。
推荐排查顺序
- 获取并保存支付 SDK 返回的
resultStatus、memo和result。 - 确认订单没有超过
time_expire。 - 使用新的
out_trade_no重新生成订单。 - 比较服务端生成的订单字符串和 APP 实际收到的字符串。
- 确认 APP 没有再次编码、解码或拼接参数。
- 核对
app_id、应用私钥、支付宝公钥和RSA2配置。 - 检查 App 支付签约状态、应用上线状态以及商户风险提示。
- 使用
alipay.trade.query查询订单是否已经创建及当前交易状态。 - 如果仍无法定位问题,整理支付宝返回的错误信息、订单号和调用时间等信息,联系支付宝技术支持。
客户端显示支付成功,也不能直接作为到账依据。服务端应先验证异步通知的签名,并结合 alipay.trade.query 确认交易状态,然后再执行充值、发货或记账操作。
备注:内容仅供参考。
