PAYATHON 2026

APP 唤起支付宝支付时提示交易订单处理失败

支付老李

结论

“交易订单处理失败,请稍后重试”是支付宝客户端的通用提示,仅凭这句话无法判断具体原因。排查 alipay.trade.app.pay 时,先检查以下几项:

  1. 服务端签名所用的应用私钥,是否与当前 app_id 配置的应用公钥配对,相关支付宝公钥或应用公钥证书是否配置正确。
  2. 服务端生成完整订单字符串后,APP 是否又对其进行了解码、拼接、排序或二次 URL 编码。
  3. 应用是否已经签约并开通 App 支付能力,调用环境、网关和密钥配置是否属于同一套环境。
  4. out_trade_no 是否重复,time_expire 是否已经过期。
  5. 手机与服务端的时间和时区是否正确。

示例请求中的 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、网关、应用私钥、支付宝公钥和产品签约状态。

推荐排查顺序

  1. 获取并保存支付 SDK 返回的 resultStatus、memo 和 result。
  2. 确认订单没有超过 time_expire。
  3. 使用新的 out_trade_no 重新生成订单。
  4. 比较服务端生成的订单字符串和 APP 实际收到的字符串。
  5. 确认 APP 没有再次编码、解码或拼接参数。
  6. 核对 app_id、应用私钥、支付宝公钥和 RSA2 配置。
  7. 检查 App 支付签约状态、应用上线状态以及商户风险提示。
  8. 使用 alipay.trade.query 查询订单是否已经创建及当前交易状态。
  9. 如果仍无法定位问题,整理支付宝返回的错误信息、订单号和调用时间等信息,联系支付宝技术支持。

客户端显示支付成功,也不能直接作为到账依据。服务端应先验证异步通知的签名,并结合 alipay.trade.query 确认交易状态,然后再执行充值、发货或记账操作。

备注:内容仅供参考。