PAYATHON 2026

H5 支付完成后如何配置“完成”页的跳转 URL?

支付阿杰

结论

H5 支付完成后的“完成”页地址,需要在调用支付宝手机网站支付接口 alipay.trade.wap.pay 时通过 return_url 设置。

return_url 仅用于支付完成后的浏览器同步跳转,不能作为判断支付是否成功的唯一依据。订单的最终状态应以支付宝发送到 notify_url 的异步通知为准,也可以由服务端主动调用查单接口确认。

配置方式

创建支付请求时,需要同时设置以下两个地址:

  • return_url:用户完成支付后跳转的页面地址。
  • notify_url:支付宝向商家服务端发送支付结果的异步通知地址。

以 Java SDK 为例:

AlipayClient alipayClient = new DefaultAlipayClient(
    gatewayUrl,
    appId,
    merchantPrivateKey,
    "json",
    "UTF-8",
    alipayPublicKey,
    "RSA2"
);

AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();

request.setReturnUrl("https://www.example.com/pay/complete");
request.setNotifyUrl("https://api.example.com/alipay/notify");

AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
model.setOutTradeNo("ORDER_202609130001");
model.setTotalAmount("99.00");
model.setSubject("订单支付");
model.setProductCode("QUICK_WAP_WAY");

request.setBizModel(model);

// pageExecute 返回可直接输出给浏览器的支付页面或表单内容
AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);

if (response.isSuccess()) {
    String paymentHtml = response.getBody();
    // 将 paymentHtml 输出给浏览器
}

较早版本的 SDK 可能通过业务参数字符串传递支付参数。不过,return_url 和 notify_url 通常仍是请求级公共参数,不应放入 biz_content:

AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();

request.setReturnUrl("https://www.example.com/pay/complete");
request.setNotifyUrl("https://api.example.com/alipay/notify");

request.setBizContent("""
{
  "out_trade_no": "ORDER_202609130001",
  "total_amount": "99.00",
  "subject": "订单支付",
  "product_code": "QUICK_WAP_WAY"
}
""");

String paymentHtml = alipayClient.pageExecute(request).getBody();

支付宝 SDK 的具体类名和方法签名可能因版本而异,请以项目实际使用的版本为准。

“完成”页应如何处理

用户通过 return_url 返回后,完成页不应直接显示“支付成功”。可以按以下流程确认支付结果:

  1. 从跳转参数中取得商户订单号等信息。
  2. 由服务端验签,不直接信任浏览器传入的参数。
  3. 根据商户订单号查询本地订单状态。
  4. 如果尚未收到异步通知,由服务端调用支付宝查单接口确认。
  5. 按实际状态显示“支付成功”“处理中”或“支付失败”。

例如,完成页可以调用商家自己的订单查询接口:

async function loadPaymentResult(outTradeNo) {
  const response = await fetch(
    `/api/orders/${encodeURIComponent(outTradeNo)}/payment-status`
  );

  const result = await response.json();

  if (result.status === "PAID") {
    window.location.replace(`/orders/${encodeURIComponent(outTradeNo)}/success`);
  } else if (result.status === "PENDING") {
    // 显示“支付结果确认中”,随后轮询或允许用户手动刷新
  } else {
    // 显示未支付或支付失败
  }
}

为什么不能只依赖 return_url

以下情况都可能导致同步跳转没有发生:

  • 用户支付后直接关闭支付宝或浏览器。
  • 网络中断。
  • 页面被系统回收。
  • 用户手动返回其他页面。
  • 浏览器拦截了跳转。

同样,用户能够访问完成页,也不代表订单一定支付成功。发货、充值、开通权益等业务操作,必须由服务端根据可靠的支付结果触发。

异步通知可以按下面的基本结构处理:

@PostMapping("/alipay/notify")
public String handleAlipayNotify(HttpServletRequest request) {
    Map<String, String> params = extractParameters(request);

    boolean valid = AlipaySignature.rsaCheckV1(
        params,
        alipayPublicKey,
        "UTF-8",
        "RSA2"
    );

    if (!valid) {
        return "failure";
    }

    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");

    // 还应核对 app_id、订单金额、商户订单号、收款方等信息。
    if ("TRADE_SUCCESS".equals(tradeStatus)
            || "TRADE_FINISHED".equals(tradeStatus)) {
        // 以幂等方式更新订单,避免重复通知导致重复发货或重复入账。
        markOrderAsPaid(outTradeNo, totalAmount, appId);
    }

    return "success";
}

注意事项

  • return_url 和 notify_url 应是外网可以访问的完整 URL,生产环境建议使用 HTTPS。
  • notify_url 必须允许支付宝服务器直接访问,不能依赖登录状态,也不能使用仅限内网访问的地址。
  • 两者用途不同:return_url 面向用户浏览器,notify_url 面向支付宝服务器。
  • 支付结果通知可能重复发送,因此订单更新必须具备幂等性。
  • 即使验签通过,也要核对 app_id、out_trade_no、total_amount、交易状态和收款方信息,不能只检查 trade_status。
  • 不要根据前端传入的订单号和支付状态直接更新订单。
  • 二维码只负责引导用户进入商家订单页。“完成”页地址不配置在二维码中,而是在订单页发起 alipay.trade.wap.pay 请求时设置。
  • 如果实际调用的不是 alipay.trade.wap.pay,而是当面付、预创建支付或其他产品,返回机制可能有所不同,需要按照对应支付产品提供的接口能力处理。

备注:内容仅供参考。