H5支付调起支付宝后未跳转到配置的回调页面
结论
支付完成后页面直接关闭,通常不代表支付失败。先确认配置的是哪种回调:
notify_url是支付宝服务器发给商户服务器的异步通知,不会让浏览器跳转。return_url是支付完成后的前端同步跳转地址。- 即使设置了
return_url,用户关闭支付宝、WebView 生命周期变化、App Scheme 拉起方式或网络异常,都可能导致同步跳转没有执行。因此,订单状态必须以服务端异步通知或主动查询结果为准,不能依赖回跳页面判断支付是否成功。
先确认实际调用的支付产品
H5 页面支付应使用手机网站支付接口:
alipay.trade.wap.pay
业务参数通常需要包含:
{
"product_code": "QUICK_WAP_WAY"
}
如果实际调用的是 alipay.trade.app.pay,支付宝会按 App 支付流程处理,不能期待它通过 H5 支付的 return_url 返回网页。
确认请求中确实包含 return_url
不能只看后台或配置文件中的地址,还要检查最终提交给支付宝的请求是否包含 return_url。
Java SDK 示例:
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.setReturnUrl("https://m.example.com/pay/result");
request.setNotifyUrl("https://api.example.com/alipay/notify");
AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
model.setOutTradeNo("ORDER_202609090001");
model.setTotalAmount("0.01");
model.setSubject("订单支付");
model.setProductCode("QUICK_WAP_WAY");
request.setBizModel(model);
AlipayTradeWapPayResponse payResponse = alipayClient.pageExecute(request);
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(payResponse.getBody());
不同版本的支付宝 Java SDK 在模型类或方法签名上可能略有差异,请以项目当前使用的 SDK 为准。需要注意以下几点:
- 在支付请求对象上设置
return_url。 - 将
notify_url设置为服务端可以访问的通知接口。 - 把
pageExecute()返回的完整 HTML 表单输出给浏览器。 - 签名完成后不要手工修改或拼接
return_url,否则可能导致验签失败,或者参数无法生效。
如果通过网关参数自行组装请求,重点检查最终请求是否包含以下字段:
method=alipay.trade.wap.pay
return_url=https://m.example.com/pay/result
notify_url=https://api.example.com/alipay/notify
排查回调地址
return_url 最好满足以下条件:
- 使用完整的绝对地址,例如
https://m.example.com/pay/result。 - 可以从公网直接访问。
- 页面打开不依赖当前浏览器的 Session。
- 不会立即被登录拦截器、网关或前端路由跳转到其他页面。
- 查询参数已正确编码。
- HTTPS 证书完整且有效。
- 页面不受只能在微信、企业 WebView 或特定 App 容器中运行的限制。
可以分别在普通浏览器和支付宝内置浏览器中直接访问该地址,确认页面不会报错、白屏或自动关闭。
如果地址中需要携带订单号,不要直接拼接未经编码的参数:
String returnUrl =
"https://m.example.com/pay/result?out_trade_no="
+ URLEncoder.encode(outTradeNo, StandardCharsets.UTF_8);
request.setReturnUrl(returnUrl);
检查 H5 拉起支付宝的方式
如果业务页面运行在自有 App 的 WebView 中,通常会通过 URL Scheme 拉起支付宝。支付完成后,支付宝可能返回原应用、关闭中间页,也可能由宿主 App 接管页面生命周期。
这种情况下需要同时检查:
- WebView 是否拦截了支付宝相关 URL。
- 拉起支付宝后,原支付页面是否已被销毁。
- App 恢复到前台时是否主动关闭了 WebView。
- 是否通过临时页面打开支付表单,并在离开页面时自动将其关闭。
- iOS 或 Android 是否只配置了 App Scheme 返回逻辑,没有保留 H5 浏览器的回跳链路。
如果业务要求稳定返回自有 App,应在 App 中设计明确的返回链路,并在 App 恢复到前台后向服务端查询订单状态。网页的 return_url 不能代替 App 回调机制。
正确处理支付结果
同步跳转只适合展示结果页,不能作为订单入账的依据。推荐采用以下流程:
用户支付
↓
支付宝异步通知 notify_url
↓
商户服务端验签并更新订单
↓
return_url 结果页查询商户订单状态
↓
未确认时轮询或提示“支付结果确认中”
结果页不能只根据 URL 参数显示“支付成功”,而应查询自己的订单接口:
async function waitForPayment(outTradeNo) {
for (let i = 0; i < 10; i++) {
const response = await fetch(
`/api/orders/${encodeURIComponent(outTradeNo)}/status`,
{ credentials: "include" }
);
const result = await response.json();
if (result.status === "PAID") {
window.location.replace("/pay/success");
return;
}
await new Promise(resolve => setTimeout(resolve, 2000));
}
window.location.replace("/pay/pending");
}
处理异步通知
notify_url 接口需要完成以下操作:
- 使用支付宝公钥验签。
- 校验
app_id、商户身份、订单号和金额。 - 根据
trade_status幂等更新订单。 - 处理成功后返回纯文本
success。 - 不要返回 JSON、HTML 或包含额外空格的内容。
示意代码:
Map<String, String> params = new HashMap<>();
request.getParameterMap().forEach((key, values) -> {
if (values != null && values.length > 0) {
params.put(key, String.join(",", values));
}
});
boolean valid = AlipaySignature.rsaCheckV1(
params,
alipayPublicKey,
"UTF-8",
"RSA2"
);
if (!valid) {
response.getWriter().write("failure");
return;
}
String outTradeNo = params.get("out_trade_no");
String tradeStatus = params.get("trade_status");
String totalAmount = params.get("total_amount");
String appId = params.get("app_id");
boolean orderValid = orderService.checkOrder(
outTradeNo,
totalAmount,
appId
);
if (!orderValid) {
response.getWriter().write("failure");
return;
}
if ("TRADE_SUCCESS".equals(tradeStatus)
|| "TRADE_FINISHED".equals(tradeStatus)) {
orderService.markPaidIdempotently(
outTradeNo,
params.get("trade_no")
);
}
response.setContentType("text/plain;charset=UTF-8");
response.getWriter().write("success");
建议按以下顺序排查
- 确认调用的接口是
alipay.trade.wap.pay。 - 确认最终支付请求中确实包含
return_url。 - 分清
return_url和notify_url,不要把异步通知地址当成前端跳转地址。 - 确认
return_url可以在支付宝内置浏览器中正常访问。 - 检查是否通过自有 App、WebView 或 Scheme 拉起支付宝,以及原页面是否被宿主关闭。
- 查看服务端是否收到发送到
notify_url的通知。 - 如果没有收到通知,检查公网访问、HTTPS、验签日志和接口响应内容。
- 对支付状态不确定的订单,通过
alipay.trade.query主动查询并进行补偿。
“页面回跳”和“支付确认”需要分开处理。return_url 用于完成前端跳转和结果展示,notify_url 与订单查询用于保证资金状态一致。
备注:内容仅供参考。
