手机网站支付调起支付宝时提示交易订单处理失败
结论
能生成支付 HTML,只能说明支付宝 SDK 已经组装好请求参数,不能证明支付宝已成功创建交易。
调起支付后出现“交易订单处理失败,请稍后再试”,通常表示支付宝网关在校验请求时拒绝了这笔交易。可以先检查业务参数、签名和密钥配置、网关环境,以及应用是否具备手机网站支付权限。仅凭这条提示无法判断具体原因,仍需查看支付宝网关返回的 code、sub_code、sub_msg 或开放平台日志。
常见原因
1. 必填业务参数有误
手机网站支付使用 alipay.trade.wap.pay,需要重点检查以下参数:
out_trade_no:商户订单号不能为空,而且在同一商户下必须唯一。total_amount:必须是合法的金额字符串,例如"0.01",不能包含货币符号,也不要使用科学计数法。subject:订单标题不能为空。product_code:手机网站支付通常应设置为QUICK_WAP_WAY。quit_url:用户取消支付后的跳转地址。return_url:同步跳转地址,应填写浏览器可以访问的完整 URL。
重复使用已经支付、已经关闭,或者前后参数不一致的 out_trade_no,也可能导致交易无法继续。
2. 应用、密钥和网关不属于同一环境
以下配置必须来自同一套环境:
app_id- 应用私钥
- 支付宝公钥
- 支付宝网关地址
- 商户签约产品
例如,沙箱应用不能调用正式网关,正式应用的密钥也不能用于沙箱环境。RSA 和 RSA2 的签名方式及密钥类型同样不能混用。
常用网关如下:
正式环境:https://openapi.alipay.com/gateway.do
沙箱环境:https://openapi-sandbox.dl.alipaydev.com/gateway.do
具体使用哪个网关,应以应用当前所在的环境和支付宝开放平台配置为准。
3. 应用未签约或没有对应权限
即使 SDK 可以生成 HTML,如果应用没有开通手机网站支付、签约状态异常,或者应用与实际收款商户不匹配,支付宝网关仍可能拒绝交易。
请在支付宝开放平台确认:
- 应用已经上线,或者当前状态允许调用接口;
- 手机网站支付产品已经签约并生效;
- 当前
app_id对应的商户与收款主体一致; - 接口调用权限、账号状态和风控状态正常。
4. HTML 被转义或错误嵌入页面
SDK 返回的内容通常是一个自动提交的表单。服务端应将它作为 HTML 原样返回给浏览器。通过模板引擎输出时,表单标签可能被转义为普通文本。如果先将表单包装成 JSON,再由前端错误拼接,也可能破坏隐藏参数或签名。
建议明确设置响应头:
Content-Type: text/html; charset=UTF-8
不要修改 SDK 生成表单中的参数,也不要对已经签名的参数再次编码或重新排序。
5. 字符集或签名配置错误
建议统一使用:
charset=utf-8
sign_type=RSA2
还要检查以下配置:
- 应用私钥是否与开放平台中配置的应用公钥匹配;
- 验签时使用的是否为支付宝公钥,而不是应用公钥;
- 私钥格式是否符合当前 SDK 的要求;
charset、sign_type是否与初始化配置一致;- 生成签名后是否又修改过请求参数。
正确的调用示例
下面的示例使用支付宝 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"
);
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.setReturnUrl("https://www.example.com/pay/alipay/return");
request.setNotifyUrl("https://www.example.com/pay/alipay/notify");
AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
model.setOutTradeNo("ORDER_202609090001");
model.setTotalAmount("0.01");
model.setSubject("测试订单");
model.setProductCode("QUICK_WAP_WAY");
model.setQuitUrl("https://www.example.com/order");
request.setBizModel(model);
AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
if (!response.isSuccess()) {
throw new IllegalStateException(
"支付宝请求失败,code=" + response.getCode()
+ ", subCode=" + response.getSubCode()
+ ", subMsg=" + response.getSubMsg()
);
}
String formHtml = response.getBody();
控制器应直接输出表单 HTML:
@GetMapping(value = "/pay/alipay", produces = "text/html;charset=UTF-8")
@ResponseBody
public String pay() throws AlipayApiException {
AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
if (!response.isSuccess()) {
throw new IllegalStateException(
response.getCode() + ": " + response.getSubMsg()
);
}
return response.getBody();
}
排查步骤
- 为这次请求使用一个全新的
out_trade_no,并用最小合法金额测试。 - 确认接口是
alipay.trade.wap.pay,product_code是QUICK_WAP_WAY。 - 核对
app_id、应用私钥、支付宝公钥和网关是否来自同一环境。 - 确认手机网站支付产品已经签约并生效。
- 查看 SDK 返回对象中的
code、msg、sub_code和sub_msg。 - 在支付宝开放平台的接口调用日志中,根据请求时间、
app_id或订单号查找失败记录。 - 使用浏览器开发者工具检查最终提交到网关的表单,确认字段没有被模板转义、截断或二次编码。
- 服务端记录支付宝响应时应做好脱敏,不要打印应用私钥、完整签名或用户敏感信息。
注意事项
不能只依赖 return_url 判断支付结果。同步跳转可能被用户关闭、拦截或伪造。订单的最终状态应以 notify_url 收到的异步通知为准,并使用支付宝公钥验签,必要时再调用交易查询接口确认。
如果返回对象显示成功,但支付宝页面仍然只有通用错误,请提供脱敏后的 app_id、接口名称、请求时间、out_trade_no、网关 code/sub_code 和开放平台日志编号,以便继续定位。不要公开应用私钥、完整签名或用户身份信息。
备注:内容仅供参考。
