PAYATHON 2026

java app支付宝支付交易订单处理失败如何解决?

支付阿杰

结论

这组参数有两个明显问题:

  1. productCode 使用了 FAST_INSTANT_TRADE_PAY。调用 alipay.trade.app.pay 时,通常应使用 QUICK_MSECURITY_PAY。FAST_INSTANT_TRADE_PAY 主要用于电脑网站支付,与 App 支付接口不匹配。
  2. biz_content 使用了 outTradeNo、productCode、timeoutExpress、totalAmount 等字段名,而支付宝接口接收的 JSON 字段名是 out_trade_no、product_code、timeout_express、total_amount。如果 JSON 是手工拼接的,支付宝可能无法正确识别这些参数。

目前只有订单字符串,无法判断签名是否正确。验签还需要参与签名的原始参数串、应用私钥所对应的支付宝公钥,以及实际的编码过程。建议先修正业务参数,再通过支付宝 Java SDK 生成订单字符串,避免手工拼接和 URL 编码。

当前参数中的主要问题

URL 解码后的 biz_content 大致如下:

{
  "body": "boy",
  "outTradeNo": "20240724102917A001",
  "productCode": "FAST_INSTANT_TRADE_PAY",
  "subject": "Subject",
  "timeoutExpress": "30m",
  "totalAmount": "100.00"
}

建议改为:

{
  "body": "boy",
  "out_trade_no": "20240724102917A001",
  "product_code": "QUICK_MSECURITY_PAY",
  "subject": "Subject",
  "timeout_express": "30m",
  "total_amount": "100.00"
}

还需要注意以下几点:

  • Java 对象的属性可以命名为 outTradeNo,但最终发送给支付宝的 JSON 字段必须符合接口定义。
  • 使用官方 SDK 的 AlipayTradeAppPayModel 时,SDK 会处理字段映射。如果使用 Map、第三方 JSON 工具或手工拼接字符串,就必须自行使用下划线字段名。
  • FAST_INSTANT_TRADE_PAY 不适用于 App 支付订单。
  • out_trade_no 在当前商户范围内必须唯一。重复提交时,需要确认旧订单是否已经创建。

推荐的 Java 实现

不要直接拼接查询字符串,也不要在签名前单独对部分参数进行 URL 编码。可以让支付宝 SDK 完成参数序列化、签名和订单字符串生成:

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;

public class AlipayOrderService {

    private static final String GATEWAY =
            "https://openapi.alipay.com/gateway.do";

    public String createOrder() throws AlipayApiException {
        String appId = "你的应用 App ID";
        String merchantPrivateKey = "你的应用私钥";
        String alipayPublicKey = "支付宝公钥";

        AlipayClient alipayClient = new DefaultAlipayClient(
                GATEWAY,
                appId,
                merchantPrivateKey,
                "json",
                "UTF-8",
                alipayPublicKey,
                "RSA2"
        );

        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setOutTradeNo("20240724102917A001");
        model.setProductCode("QUICK_MSECURITY_PAY");
        model.setSubject("Subject");
        model.setBody("boy");
        model.setTotalAmount("100.00");
        model.setTimeoutExpress("30m");

        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        request.setBizModel(model);
        request.setNotifyUrl("https://saas.a1a9.com/api/alipay/notify");

        AlipayTradeAppPayResponse response =
                alipayClient.sdkExecute(request);

        if (!response.isSuccess()) {
            throw new IllegalStateException(
                    "生成支付宝订单失败:" +
                    response.getCode() + " / " +
                    response.getSubCode() + " / " +
                    response.getSubMsg()
            );
        }

        return response.getBody();
    }
}

response.getBody() 返回的就是应交给支付宝 App SDK 的完整订单字符串。客户端不要调整字段顺序、重新签名,也不要再次对整个字符串进行 URL 编码。

签名排查方法

修正参数后如果仍然失败,可以按以下顺序检查。

1. 确认密钥对应关系

DefaultAlipayClient 中应配置:

  • 商户应用私钥,不能使用支付宝私钥或应用公钥;
  • 支付宝公钥,不能使用商户应用公钥;
  • sign_type 使用 RSA2 时,密钥配置也必须与 RSA2 签名方式匹配;
  • 当前私钥必须与支付宝开放平台中该 app_id 配置的应用公钥对应。

如果应用重新上传过公钥,而服务端仍在使用旧私钥,签名一定无法通过。

2. 检查环境是否一致

正式环境通常使用:

https://openapi.alipay.com/gateway.do

沙箱应用必须同时使用沙箱网关、沙箱 App ID 和沙箱密钥,不能与正式环境的配置混用。

3. 不要二次编码订单字符串

签名是根据特定的参数内容计算出来的。签名完成后,以下操作都可能破坏签名:

  • 对整个订单字符串再次调用 URLEncoder.encode();
  • 解码后重新组装参数;
  • 修改 biz_content;
  • 混用 +、空格和 %2B;
  • 按自定义规则重新排序或过滤参数。

服务端应将 sdkExecute() 返回的字符串原样传给 App。

4. 检查服务器时间

示例中的 timestamp=2024-07-24 10:29:18 已经过期,不能继续用这条历史订单字符串发起支付。每次创建订单时都应实时生成参数和签名,并确保服务器时间准确。

回调地址检查

当前 notify_url 使用的是 HTTP:

http://saas.a1a9.com/api/alipay/notify

这通常不会直接引发“交易订单处理失败”,但生产环境建议改用公网可访问的 HTTPS 地址。回调接口还应满足以下要求:

  • 支付宝服务器可以直接访问;
  • 不要求登录,也不依赖 Cookie 或验证码;
  • 不会被防火墙、网关鉴权或 CSRF 校验拦截;
  • 收到通知后使用支付宝公钥验签;
  • 验签成功并完成业务处理后,返回纯文本 success;
  • 不依赖参数顺序,也不在验签前修改参数值。

回调验签失败不会让用户在创建订单时立即看到报错,但会导致支付完成后无法正确更新业务订单。

获取真正的失败原因

“交易订单处理失败”只是客户端显示的概括性提示,单凭这句话无法判断问题出在签名、权限还是业务参数。服务端应完整记录以下字段:

response.getCode();
response.getMsg();
response.getSubCode();
response.getSubMsg();
response.getBody();

排查时重点查看 sub_code 和 sub_msg。常见原因包括:

  • 应用未开通 App 支付能力;
  • 应用、商户账号或签约产品不匹配;
  • app_id 与密钥不匹配;
  • product_code 错误;
  • out_trade_no 重复;
  • 金额或必填字段格式错误;
  • 签名前后参数被修改;
  • 正式环境与沙箱配置混用。

建议先将 product_code 改为 QUICK_MSECURITY_PAY,使用 AlipayTradeAppPayModel 和 sdkExecute() 重新生成订单字符串,再根据支付宝返回的 sub_code 排查其余问题。

备注:内容仅供参考。