PAYATHON 2026

支付宝沙箱支付提示“订单信息有错误”是什么原因?

支付老李

结论

支付宝提示”订单信息有错误,建议重新下单后付款”,说明订单校验没有通过。单凭这个页面,还无法确定具体原因。

项目搁置一段时间后再次测试,常见原因包括:

  • 复用了以前的 out_trade_no,而原订单已经支付、关闭或状态异常。
  • 订单创建时间太早,或者 timeout_express 设置的有效期已经结束。
  • 沙箱环境中的 app_id、密钥、证书、网关地址或沙箱账号发生了变化。
  • 请求参数不合法,例如金额格式错误、必填参数为空或签名失败。
  • 正式环境和沙箱环境的配置混用。

排查时不要只看支付页面。先检查支付宝接口返回的 code、sub_code 和 sub_msg,这些字段通常能说明更具体的失败原因。

优先检查订单号

支付宝商户订单号 out_trade_no 在商户系统中必须唯一。重新运行旧项目时,如果代码写死了订单号,就可能再次提交一个已经存在的订单。

下面这种写法很容易造成订单号重复:

model.setOutTradeNo("202401010001");

测试时应为每笔订单生成新的订单号:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ThreadLocalRandom;

public class OrderNoGenerator {

    public static String generate() {
        String time = LocalDateTime.now()
                .format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
        int random = ThreadLocalRandom.current().nextInt(1000, 10000);
        return time + random;
    }
}

创建支付请求时使用新订单号:

AlipayTradePagePayModel model = new AlipayTradePagePayModel();
model.setOutTradeNo(OrderNoGenerator.generate());
model.setTotalAmount("0.01");
model.setSubject("沙箱支付测试");
model.setProductCode("FAST_INSTANT_TRADE_PAY");
model.setTimeoutExpress("15m");

正式项目中的订单号应由业务系统统一生成并持久化,不能只依赖随机数,也不能在用户每次刷新页面时都生成新订单。

检查订单是否已经过期

如果项目保存了以前创建的订单,再次打开支付页面时,该订单可能已经超过允许支付的时间。

需要检查:

  • 是否复用了数据库中的旧订单。
  • timeout_express 是否设置得太短。
  • 服务器时间和时区是否正确。
  • 订单是否已被支付宝关闭。
  • 本地订单状态是否与支付宝侧一致。

遇到旧订单时,应先调用订单查询接口确认状态,不要直接再次发起支付:

AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent("""
{
  "out_trade_no": "实际商户订单号"
}
""");

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());
System.out.println("tradeStatus=" + response.getTradeStatus());

如果订单已经关闭,应创建新的业务订单,或按照业务规则生成新的支付订单,不能继续使用原来的 out_trade_no。

核对沙箱配置

沙箱环境中的配置必须成套使用,不能只替换其中一部分。至少要核对以下内容:

  • app_id 是否属于当前沙箱应用。
  • 应用私钥是否与上传到支付宝的应用公钥匹配。
  • 使用证书模式时,应用证书、支付宝公钥证书和支付宝根证书是否配套。
  • 网关地址是否为沙箱网关。
  • 签名算法是否与应用配置一致,通常为 RSA2。
  • 支付账号是否为沙箱提供的买家账号。
  • 后端是否误读了正式环境的配置文件或环境变量。

普通公钥模式的配置示例如下:

AlipayClient alipayClient = new DefaultAlipayClient(
        "https://openapi-sandbox.dl.alipaydev.com/gateway.do",
        appId,
        merchantPrivateKey,
        "json",
        "UTF-8",
        alipayPublicKey,
        "RSA2"
);

不同的 SDK 版本或接入模式可能使用不同的构造方法。如果采用证书模式,应使用对应的证书客户端配置,不能把支付宝公钥字符串和证书模式混在一起使用。

检查请求参数

发起网页支付时,重点检查这些参数:

参数检查内容
out_trade_no非空,长度符合接口要求,并且未被其他订单使用
total_amount使用字符串形式的合法金额,如 "0.01",不能为零或负数
subject非空,避免包含异常控制字符
product_code网页支付通常使用 FAST_INSTANT_TRADE_PAY
timeout_express格式正确,如 15m、1h
notify_url支付宝服务器可以访问,不能使用仅本机可见的地址
return_urlURL 格式正确
charset与签名及客户端配置一致
sign_type与应用密钥配置一致

金额最好使用 BigDecimal 处理,以免出现浮点数精度问题:

import java.math.BigDecimal;
import java.math.RoundingMode;

BigDecimal amount = new BigDecimal("0.01")
        .setScale(2, RoundingMode.UNNECESSARY);

model.setTotalAmount(amount.toPlainString());

不要用下面这种方式计算支付金额:

double amount = 0.1 + 0.2;
model.setTotalAmount(String.valueOf(amount));

double 可能得到类似 0.30000000000000004 的结果,导致金额或业务校验异常。

输出完整的支付宝响应

使用 alipay.trade.page.pay 时,应记录响应中的诊断字段:

AlipayTradePagePayResponse response = alipayClient.pageExecute(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());
System.out.println("body=" + response.getBody());

if (!response.isSuccess()) {
    throw new IllegalStateException(
            "支付宝下单失败,code=" + response.getCode()
                    + ", subCode=" + response.getSubCode()
                    + ", subMsg=" + response.getSubMsg()
    );
}

常见问题包括:

  • 签名验证失败。
  • 商户订单号重复。
  • 参数缺失或格式错误。
  • 应用没有接口权限。
  • 应用、账号或密钥不匹配。
  • 订单已经关闭,无法再次支付。

错误的具体含义应以接口实际返回的 sub_code 和 sub_msg 为准,不能只根据前端提示判断。

建议的排查顺序

  1. 为本次测试生成全新的 out_trade_no。
  2. 将支付金额固定为 "0.01",排除金额计算问题。
  3. 确认程序没有读取以前保存的订单或过期支付链接。
  4. 核对沙箱的 app_id、网关、密钥或证书,以及买家账号。
  5. 打印接口返回的 code、sub_code 和 sub_msg。
  6. 调用订单查询接口,确认旧订单是否已支付或关闭。
  7. 根据具体错误码检查签名、权限和请求参数。

如果换用新订单号后恢复正常,通常说明旧订单号被重复使用,或者原订单已经失效。如果新订单仍然报错,应重点检查沙箱配置和接口响应中的具体错误信息。

备注:内容仅供参考。