PAYATHON 2026

orderStr 调用客户端支付接口后无法唤起支付宝

支付阿杰

结论

这段 orderStr 的结构符合支付宝 App 支付参数串的常见格式,biz_content、notify_url、sign 和 timestamp 也做了 URL 编码。单看字符串无法判断签名是否正确,但有两个问题需要优先检查:

  1. alipay_sdk=alipay-sdk-java-dynamicVersionNo 很像 Java SDK 构建时未正确替换的版本占位值。建议升级或重新引入正式发布的支付宝 Java SDK,并通过 SDK 的 sdkExecute 生成订单串。
  2. 示例订单的创建时间是 2024-08-02 17:54:57,timeout_express=30m。如果现在还在用这段固定内容测试,订单已经过期,需要重新生成 out_trade_no、timestamp 和签名。

如果客户端完全没有打开支付宝,应先检查客户端 SDK 集成、调用线程,以及传参过程中是否发生了解码或二次编码。如果能够打开支付宝,但支付失败,则重点检查签名、应用配置和订单参数。

不要手工修改或重新编码 orderStr

服务端完成签名并将 orderStr 返回给客户端后,客户端应把原字符串直接传给支付宝支付 SDK。

以下操作都会改变签名对应的内容:

  • 对整个 orderStr 再调用一次 URLEncoder.encode
  • 先调用 URLDecoder.decode,再传给客户端 SDK
  • 将字符串解析成对象后重新拼接
  • 改变参数顺序
  • 将 + 自动转换为空格,或者将 %2B 转换成 +
  • 通过 JSON、表单或网关传输时发生转义或截断
  • 在字符串两侧添加引号、空格或换行

服务端通过 JSON 返回时,可以使用普通字符串字段:

{
  "orderStr": "alipay_sdk=...&app_id=...&biz_content=...&sign=...&sign_type=RSA2..."
}

客户端取出 orderStr 后直接调用支付接口,不要再做 URL 编解码。

服务端应使用 sdkExecute 生成订单串

Java 服务端可以参考下面的写法。具体 SDK 版本和构造函数参数,以项目实际使用的支付宝 Java SDK 为准:

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

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

AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setBody("sheyipai");
model.setSubject("珍珠项链 一套价格德国小众饰品");
model.setOutTradeNo(generateUniqueOrderNo());
model.setTimeoutExpress("30m");
model.setTotalAmount("461.00");
model.setProductCode("QUICK_MSECURITY_PAY");

request.setBizModel(model);

// sdkExecute 生成的 body 才是传给客户端支付 SDK 的 orderStr
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
String orderStr = response.getBody();

不要自行拼接参数后再单独处理 sign。SDK 会按规定完成参数排序、签名和 URL 编码。

alipay_sdk-java-dynamicVersionNo 通常不是正常的最终版本标识,可能与非正式构建包、依赖冲突或 SDK 资源过滤异常有关。建议检查依赖树,排除重复或来源不明的支付宝 SDK:

mvn dependency:tree

然后确认项目实际引入的是正式发布版本。不要通过手工删除 alipay_sdk 参数来处理这个问题。签名已经根据原参数生成,修改任何参数后都必须重新签名。

客户端调用方式

Android

支付调用应放在非主线程中,同时记录 SDK 的返回结果:

Runnable payRunnable = () -> {
    PayTask payTask = new PayTask(activity);

    // orderStr 必须是服务端原样返回的字符串
    Map<String, String> result = payTask.payV2(orderStr, true);

    Log.d("AliPay", "pay result: " + result);
};

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

需要检查:

  • 项目是否正确集成支付宝客户端 SDK
  • 传入的 Activity 是否有效
  • 调用时 Activity 是否仍处于可用状态
  • orderStr 是否为空、被截断或带有额外引号
  • 混淆、ABI 或依赖冲突是否导致 SDK 初始化异常
  • 是否记录了 payV2 的完整返回值和运行时异常

iOS

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

确认 fromScheme 与应用在 Info.plist 中注册的 URL Scheme 完全一致。Scheme 配置错误可能导致支付宝无法回跳应用。如果支付宝完全没有打开,还应继续检查 SDK 集成和传入的订单字符串。

逐项检查订单参数

示例中的 biz_content 解码后,主要内容如下:

{
  "body": "sheyipai",
  "out_trade_no": "2024080217540089752",
  "product_code": "QUICK_MSECURITY_PAY",
  "subject": "珍珠项链 一套价格德国小众饰品",
  "timeout_express": "30m",
  "total_amount": "461.0"
}

这些业务参数在结构上没有明显错误,但还要逐项确认:

  • product_code 应为 QUICK_MSECURITY_PAY
  • out_trade_no 在商户系统内必须唯一
  • total_amount 应使用十进制金额字符串,建议统一写成 "461.00"
  • timestamp 必须是生成订单时的当前时间
  • charset、签名使用的字符集和业务内容编码应保持一致
  • app_id 必须与签名私钥所属的应用一致
  • 服务端配置的商户应用私钥必须与开放平台上传的应用公钥配套
  • 验签时使用支付宝公钥,不是应用公钥
  • 应用必须具备可用的 App 支付能力,调用环境也要与应用配置匹配

示例中 subject 编码里的 + 通常表示原始空格。如果原文确实包含空格,这种编码是正常的。如果业务内容需要字面意义上的加号,则应编码为 %2B。无论属于哪种情况,都应交给 SDK 统一编码,客户端不要自行替换。

根据现象区分问题位置

完全没有打开支付宝

优先检查:

  1. 客户端是否确实执行了支付调用。
  2. orderStr 是否为 null、空字符串或已被截断。
  3. 是否错误地对整个订单串做了二次 URL 编码。
  4. Android 的 Activity、线程和 SDK 依赖是否正常。
  5. iOS 的支付宝 SDK 和 URL Scheme 是否配置正确。
  6. 客户端控制台是否出现异常、崩溃或依赖加载失败。

可以在调用前记录字符串长度和摘要,但生产环境中不要完整打印签名及订单敏感信息:

Log.d("AliPay", "orderStr length = " + orderStr.length());
Log.d("AliPay", "startsWith app params = " + orderStr.startsWith("alipay_sdk="));

打开支付宝后提示订单或签名错误

重点检查:

  • app_id 与应用私钥是否匹配
  • 是否使用 RSA2
  • 参数完成签名后是否又被修改
  • 是否混用了公钥模式和证书模式
  • 是否混用了正式环境和沙箱环境
  • 订单号是否重复
  • 时间戳和订单是否已经过期
  • 服务端是否错误地使用支付宝公钥进行签名

支付完成但服务端没有收到通知

这和“无法唤起支付宝”是两个不同的问题,需要检查:

  • notify_url 是否能从公网访问
  • 是否允许支付宝通过 POST 请求访问
  • HTTPS 证书链是否完整有效
  • 请求是否被登录验证、网关、WAF 或 IP 白名单拦截
  • 异步通知验签是否正确
  • 处理成功后是否按要求返回成功响应

推荐排查顺序

  1. 重新生成一笔新订单,不要继续使用示例中的旧 timestamp 和 out_trade_no。
  2. 升级或重新安装正式的支付宝 Java SDK,处理 dynamicVersionNo 占位值问题。
  3. 服务端只通过 sdkExecute 获取 orderStr。
  4. 对比服务端生成值、接口响应值和客户端接收值,确认三者逐字符一致。
  5. 客户端不要解码、重排或二次编码,直接调用支付 SDK。
  6. 保存客户端支付接口的完整返回结果,再根据 resultStatus、memo 等字段定位问题。
  7. 如果提示签名错误,继续核对 app_id、应用私钥、支付宝公钥、签名模式和运行环境。

仅凭肉眼无法判断这段参数串的签名是否正确,但 SDK 版本占位值和过期的订单时间应当优先处理。对于“完全无法唤起支付宝”的情况,应先检查客户端集成以及订单串是否在传输过程中被修改,再排查业务参数。

备注:内容仅供参考。