PAYATHON 2026

支付宝手机网站支付是否支持支付失败或放弃支付回调?

支付小周

明确结论

支付宝手机网站支付通常没有统一、可靠的“支付失败”或“放弃支付”回调。

商户可以配置三个地址,但用途不同:

  • notify_url:接收支付宝服务端发送的异步通知,用来确认交易状态。
  • return_url:支付流程结束后,将用户浏览器同步跳转到商户页面。
  • quit_url:接口支持该参数时,用户主动点击“退出”后返回的地址。

return_url 和 quit_url 都依赖浏览器完成跳转。如果用户直接关闭页面、断网、杀死 App,或长时间停留后离开,商户无法立即收到可靠的回调。因此,不能因为“没有收到成功通知”就认定支付失败或用户放弃支付。

为什么不能依赖失败回调

支付过程可能因多种情况中断:

  • 用户主动关闭支付页面;
  • 用户点击退出或返回;
  • 网络中断,页面未能跳转;
  • 支付验证失败,但用户之后仍可能重新尝试;
  • 订单暂时处于 WAIT_BUYER_PAY,之后仍可能支付成功;
  • 支付宝超时关闭交易,状态变为 TRADE_CLOSED。

这些情况未必会触发浏览器回跳,也不能一概视为最终支付失败。支付宝服务端可以可靠确认交易状态,但无法确认用户离开页面的具体原因。

推荐配置方式

调用手机网站支付接口时,应同时配置 notify_url 和 return_url。如果所用接口版本支持 quit_url,也可以在业务参数中配置退出地址。

下面以常见的 alipay.trade.wap.pay Java SDK 调用方式为例:

AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();

request.setNotifyUrl("https://www.example.com/alipay/notify");
request.setReturnUrl("https://www.example.com/payment/result");

request.setBizContent("""
{
  "out_trade_no": "ORDER_202609090001",
  "total_amount": "99.00",
  "subject": "订单支付",
  "product_code": "QUICK_WAP_WAY",
  "quit_url": "https://www.example.com/payment/cancel"
}
""");

AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
String paymentForm = response.getBody();

quit_url 是否可用、应该放在哪里,以及允许使用哪些 URL 格式,需要以实际接入的支付宝接口文档和 SDK 版本为准。即使配置了该参数,它也只能处理用户通过支付页面指定退出入口离开的情况。

正确处理异步通知

判断订单是否支付成功,应主要依据 notify_url 收到且验签通过的异步通知,不能只看 return_url。

Map<String, String> params = new HashMap<>();

for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
    String[] values = entry.getValue();
    params.put(entry.getKey(), 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 tradeNo = params.get("trade_no");
String tradeStatus = params.get("trade_status");
String totalAmount = params.get("total_amount");
String appId = params.get("app_id");

if ("TRADE_SUCCESS".equals(tradeStatus)
        || "TRADE_FINISHED".equals(tradeStatus)) {

    // 还应核对 app_id、商户订单号、订单金额、收款方等关键字段。
    // 更新订单时必须保证幂等,避免重复通知导致重复发货。

    markOrderPaid(outTradeNo, tradeNo);
    response.getWriter().write("success");
} else {
    response.getWriter().write("success");
}

生产环境不能只验证签名,还要核对以下内容:

  • app_id 是否属于当前应用;
  • out_trade_no 是否存在;
  • total_amount 是否与本地订单金额一致;
  • 收款方信息是否与商户账户一致;
  • 订单是否已经处理,避免重复发货。

用户返回页面时如何判断结果

return_url 适合展示结果页面,不能作为最终入账依据。用户返回商户页面后,服务端应先查询本地订单。如果异步通知还未到达,可以调用交易查询接口确认状态。

AlipayTradeQueryRequest queryRequest = new AlipayTradeQueryRequest();
queryRequest.setBizContent("""
{
  "out_trade_no": "ORDER_202609090001"
}
""");

AlipayTradeQueryResponse queryResponse =
    alipayClient.execute(queryRequest);

if (queryResponse.isSuccess()) {
    String tradeStatus = queryResponse.getTradeStatus();

    if ("TRADE_SUCCESS".equals(tradeStatus)
            || "TRADE_FINISHED".equals(tradeStatus)) {
        // 核对金额等信息后,幂等更新为已支付
    } else if ("WAIT_BUYER_PAY".equals(tradeStatus)) {
        // 仍待支付,可提示用户继续支付或稍后刷新
    } else if ("TRADE_CLOSED".equals(tradeStatus)) {
        // 交易已经关闭,不能再通过该支付宝交易完成付款
    }
}

在结果尚未确认时,页面显示“正在确认支付结果”更稳妥,不要因为尚未收到成功通知就直接显示“支付失败”。

如何处理放弃支付和超时订单

商户系统需要自行维护订单有效期,可以按以下流程处理:

  1. 创建订单时记录过期时间。
  2. 尚未收到成功通知时,订单保持“待支付”状态。
  3. 用户返回后查询交易状态。
  4. 后台定时扫描超过有效期的订单。
  5. 对仍未支付的订单执行关单或标记超时。
  6. 即使本地订单已经超时,也要正确处理之后到达的异步通知,避免本地状态与支付宝状态不一致。

收到 TRADE_CLOSED 后,可以确认交易已经关闭,但不能据此认定用户主动放弃。交易也可能因超时或其他原因关闭。

注意事项

  • return_url 依赖浏览器同步跳转,可能不会发生,也可能早于异步通知到达。
  • quit_url 只能处理指定的退出入口,无法捕获关闭浏览器、断网或杀死 App 等情况。
  • 没有收到回调不等于支付失败。
  • 不要根据前端页面参数直接发货。
  • 异步通知可能重复发送,订单更新必须保证幂等。
  • 主动查询只适合作为补偿机制,不建议无间隔地高频轮询。
  • 不同支付宝产品、接口版本和 SDK 支持的参数可能不同,接入时应以实际使用接口的官方文档为准。

备注:内容仅供参考。