鸿蒙Next支付宝支付SDK升级15.8.36后无法拉起订单
结论
升级到 15.8.36 后,不建议继续使用由 mapi.alipay.com/gateway.do 生成的旧版订单串。服务端应迁移到支付宝开放平台的 alipay.trade.app.pay 接口,再将接口返回的完整订单串原样传给鸿蒙 Next 支付 SDK。
出现“系统繁忙”或不显示订单弹窗,通常不是 ArkTS 拉起代码导致的,而是新版 SDK 无法正确识别旧 mapi 订单的格式、签名方式或参数编码。只修改客户端参数,通常无法彻底解决问题。
原因分析
旧订单串一般通过以下网关和历史接口生成:
https://mapi.alipay.com/gateway.do
其中可能包含旧版服务名称、签名参数或编码规则。新版支付 SDK 对订单格式、签名算法和业务参数的校验更严格。旧订单串此前能够使用,不代表升级后仍然兼容。
SDK 只负责拉起支付宝并提交订单,订单参数和签名必须由服务端生成。客户端不能靠拼接、删改或重新编码旧订单串来适配新版 SDK,否则会导致签名失效。
问题中没有提供完整订单串、签名方式和服务端实现,因此暂时无法确定具体是哪个参数校验失败。较稳妥的处理方式是迁移到 alipay.trade.app.pay。至于 15.8.36 是否明确停止兼容旧 mapi 接口,仍需以支付宝对应版本的官方接入文档或技术支持答复为准。
解决步骤
1. 服务端改用 App 支付接口
通过支付宝开放平台 SDK 调用:
alipay.trade.app.pay
不要再将下面这种网关 URL 作为新版订单串:
https://mapi.alipay.com/gateway.do?_input_charset=utf-8&body=xxxxxx
新版订单串一般由开放平台 SDK 根据业务参数、公共参数和应用私钥生成。
2. 使用 RSA2 签名
检查支付宝开放平台中的应用公钥配置,并使用:
sign_type=RSA2
私钥只能保存在服务端,不能写入鸿蒙客户端。以下配置还必须属于同一个支付宝开放平台应用:
app_id- 应用私钥
- 支付宝公钥或支付宝公钥证书
- 签名模式
- 网关环境
如果采用证书模式,应完全按照证书模式初始化 SDK,不能混用普通公钥模式的配置。
3. 服务端生成订单串
下面是支付宝 Java SDK 的典型写法。具体类名和初始化方式应以项目实际使用的官方 SDK 版本为准:
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipay.com/gateway.do",
APP_ID,
APP_PRIVATE_KEY,
"json",
"UTF-8",
ALIPAY_PUBLIC_KEY,
"RSA2"
);
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setOutTradeNo(outTradeNo);
model.setSubject("商品名称");
model.setTotalAmount("0.01");
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
request.setNotifyUrl("https://example.com/alipay/notify");
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
if (!response.isSuccess()) {
throw new IllegalStateException(
response.getCode() + ": " + response.getSubMsg()
);
}
String orderString = response.getBody();
需要传给客户端的是:
response.getBody()
不要将 response 对象转换成 JSON,也不要把完整的开放平台网关地址传给客户端。
4. 客户端原样提交订单串
鸿蒙 Next 客户端从业务服务端取得订单串后,应原样传入 15.8.36 SDK 提供的支付方法:
const orderString = await requestOrderFromServer()
// 支付方法及返回类型以 15.8.36 SDK实际提供的 ArkTS API 为准。
const result = await alipaySdk.pay(orderString)
这里的 alipaySdk.pay 只用于说明调用结构,并不代表实际方法名。不同的鸿蒙 SDK 包、接入方式和版本可能采用不同的类名、初始化参数及回调形式,应替换为 15.8.36 接入文档中提供的真实 API。
客户端需要遵守以下要求:
- 不生成签名。
- 不拆分或重新拼接订单串。
- 不手工添加
https://mapi.alipay.com/gateway.do。 - 不对整个订单串重复执行 URL 编码或解码。
- 不将订单串包装成 JSON 后直接传给 SDK。
排查建议
迁移接口后如果仍然无法拉起支付,可以按以下顺序检查:
- 在服务端记录支付宝 SDK 最终生成的订单串。生产日志中的签名和敏感业务信息需要脱敏。
- 确认客户端收到的字符串与服务端输出完全一致,重点检查
&、+、%、引号和空格是否被中间层修改。 - 确认订单串没有在放入 URL 查询参数后被再次解码,导致
+转换成空格。 - 检查
app_id与签名私钥是否匹配。 - 检查
out_trade_no是否唯一,total_amount格式是否合法。 - 检查
product_code是否使用 App 支付要求的值:
QUICK_MSECURITY_PAY
- 检查支付宝应用是否已经签约并开通 App 支付能力。
- 查看 SDK 返回的
resultStatus、错误码或日志,不要只根据支付宝客户端显示的“系统繁忙”判断原因。 - 使用服务端新生成的订单进行测试,不要复用已经关闭、超时或支付完成的历史订单。
临时回退是否可行
如果业务必须立即恢复,可以在确认安全性和发布条件允许后,临时回退到此前能够处理旧订单串的 SDK 版本。这只能作为过渡方案,无法消除旧接口的兼容风险。
更合适的做法是保留客户端 15.8.36,尽快将服务端下单逻辑迁移到 alipay.trade.app.pay。迁移完成后,还要通过支付宝异步通知或主动查询接口确认支付结果,不能只凭客户端返回的“支付成功”进行最终入账。
备注:内容仅供参考。
