如何获取 alipay.trade.wap.pay 的响应参数?
结论
alipay.trade.wap.pay 是页面类支付接口。调用后得到的 HTTP 地址或 Form 表单只用于拉起支付宝收银台。此时交易通常还没有完成,无法直接从中获取 trade_no、trade_status 等支付结果。
这些参数应按用途从以下渠道获取:
return_url:接收支付完成后的浏览器同步跳转参数,用于展示支付结果页面。notify_url:接收支付宝服务端发送的异步通知,主要用于确认支付成功并更新订单状态。alipay.trade.query:主动查询交易状态,用于处理异步通知延迟或丢失等情况。
文档列出了响应字段,并不表示调用 pageExecute 生成支付表单时就能拿到这些支付结果。
为什么无法从支付链接中取得响应参数
调用 SDK 的 pageExecute 后,SDK 主要执行以下操作:
- 组装请求参数。
- 对请求参数签名。
- 生成自动提交的 HTML Form,或者生成支付宝网关跳转 URL。
- 由用户通过浏览器进入支付宝收银台并完成支付。
到这一步,商户服务端只是发起了支付,支付宝尚未完成交易处理。HTTP 302 跳转的目标也是支付宝收银台页面,而不是返回给商户服务端的业务 JSON。
例如:
AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
String form = response.getBody();
这里的 response.getBody() 通常是用于跳转的 HTML Form,不是支付完成后的交易结果。即使 SDK 的响应对象提供了 getTradeNo() 等方法,也不能认为这些字段在生成支付页面时一定有值。
推荐的处理流程
1. 发起支付时配置回调地址
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.setNotifyUrl("https://example.com/alipay/notify");
request.setReturnUrl("https://example.com/alipay/return");
request.setBizContent("""
{
"out_trade_no": "ORDER_202609090001",
"total_amount": "99.00",
"subject": "测试订单",
"product_code": "QUICK_WAP_WAY"
}
""");
AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
String form = response.getBody();
服务端将 form 输出给浏览器:
httpServletResponse.setContentType("text/html;charset=UTF-8");
httpServletResponse.getWriter().write(form);
httpServletResponse.getWriter().flush();
如果使用 URL 模式,则让浏览器跳转到生成的支付地址。
2. 在 return_url 中接收同步跳转参数
用户完成支付后,支付宝会尝试将浏览器跳转到 return_url。商户可以从请求参数中读取 out_trade_no、trade_no、total_amount 等字段。
@GetMapping("/alipay/return")
public String alipayReturn(HttpServletRequest request) throws Exception {
Map<String, String> params = getParameterMap(request);
boolean valid = AlipaySignature.rsaCheckV1(
params,
ALIPAY_PUBLIC_KEY,
"UTF-8",
"RSA2"
);
if (!valid) {
return "支付结果签名验证失败";
}
String outTradeNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
// 建议进一步调用 alipay.trade.query 核实交易状态
return "支付完成,商户订单号:" + outTradeNo + ",支付宝交易号:" + tradeNo;
}
如果用户关闭页面、网络中断,或者客户端未完成跳转,商户可能收不到同步跳转参数。因此,不能只依赖 return_url 更新订单状态。
3. 在 notify_url 中处理异步通知
支付宝服务器会直接向商户服务器发送异步通知,更适合用来触发订单状态变更。
@PostMapping("/alipay/notify")
@ResponseBody
public String alipayNotify(HttpServletRequest request) throws Exception {
Map<String, String> params = getParameterMap(request);
boolean valid = AlipaySignature.rsaCheckV1(
params,
ALIPAY_PUBLIC_KEY,
"UTF-8",
"RSA2"
);
if (!valid) {
return "failure";
}
String outTradeNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
String tradeStatus = params.get("trade_status");
String totalAmount = params.get("total_amount");
String appId = params.get("app_id");
String sellerId = params.get("seller_id");
// 除验签外,还应校验 app_id、seller_id、out_trade_no 和 total_amount。
if ("TRADE_SUCCESS".equals(tradeStatus)
|| "TRADE_FINISHED".equals(tradeStatus)) {
// 按 out_trade_no 幂等更新订单,避免重复通知造成重复处理。
updateOrderPaid(outTradeNo, tradeNo, totalAmount);
}
// 处理成功后必须返回纯文本 success。
return "success";
}
参数转换方法示例:
private Map<String, String> getParameterMap(HttpServletRequest request) {
Map<String, String> result = new HashMap<>();
request.getParameterMap().forEach((name, values) -> {
if (values != null && values.length > 0) {
result.put(name, String.join(",", values));
}
});
return result;
}
完成验签和业务校验,并成功处理订单后,才能向支付宝返回 success。
4. 必要时主动查询交易
如果前端已经返回,但异步通知还没有到达,可以使用商户订单号查询实际交易状态:
AlipayTradeQueryRequest queryRequest = new AlipayTradeQueryRequest();
queryRequest.setBizContent("""
{
"out_trade_no": "ORDER_202609090001"
}
""");
AlipayTradeQueryResponse queryResponse =
alipayClient.execute(queryRequest);
if (queryResponse.isSuccess()) {
String tradeNo = queryResponse.getTradeNo();
String tradeStatus = queryResponse.getTradeStatus();
String totalAmount = queryResponse.getTotalAmount();
// 校验订单号和金额后,再根据 tradeStatus 更新本地订单。
}
查询接口用于确认交易状态或补偿异步通知,不应由前端直接判断订单是否支付成功。
注意事项
- HTTP 302 成功、Form 生成成功或用户返回
return_url,都不等于支付成功。 return_url主要用于页面跳转和结果展示。订单入账应以验签通过的异步通知或主动查询结果为准。- 收到通知后,除了验证签名,还要核对
app_id、seller_id、out_trade_no、total_amount等业务字段。 - 支付宝可能重复发送异步通知,因此订单更新必须按
out_trade_no做幂等处理。 - 比较金额时,建议使用
BigDecimal或规范化后的字符串,不要直接使用double。 - 异步通知地址必须能被支付宝服务器访问,不能使用仅限本机访问的地址。
- 实际返回字段和交易状态应以当前接入模式及开放平台对应接口文档为准,不能假设每次回调都会包含文档列出的所有字段。
备注:内容仅供参考。
