PAYATHON 2026

网页应用支付成功后如何从支付宝付款页跳转至成功页面?

支付小周

结论

发起支付宝网页支付时设置 return_url,用户完成支付后,支付宝收银台会将浏览器跳转到这个地址。

return_url 只负责页面跳转,不能作为支付成功的最终依据。服务端应通过 notify_url 接收支付宝的异步通知,验签后再确认订单状态。如果用户返回成功页时异步通知尚未到达,页面应向服务端查询订单状态。

发起支付时设置跳转地址

以支付宝电脑网站支付接口 alipay.trade.page.pay 为例,支付请求中可以同时设置两个地址:

  • return_url:用户完成支付后,浏览器跳转到的地址。
  • notify_url:支付宝服务器发送异步支付结果的地址。

Java 示例:

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

AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();

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

request.setBizContent("""
{
  "out_trade_no": "ORDER_202609090001",
  "total_amount": "99.00",
  "subject": "网站订单支付",
  "product_code": "FAST_INSTANT_TRADE_PAY"
}
""");

AlipayTradePagePayResponse response = alipayClient.pageExecute(request);

if (response.isSuccess()) {
    String paymentForm = response.getBody();
    // 将 paymentForm 返回给浏览器,由浏览器提交或直接渲染
} else {
    // 记录支付宝返回的错误码和错误信息
}

return_url 和 notify_url 都应使用外网可以访问的 HTTPS 地址。不同版本的 Java SDK 在类名和调用方式上可能略有差异,但这两个地址的用途不变。

正确处理支付结果

1. 通过异步通知更新订单

支付宝会向 notify_url 发送支付结果。服务端收到通知后,需要依次处理:

  1. 获取支付宝发送的全部参数。
  2. 使用支付宝公钥验证签名。
  3. 校验 app_id、商户订单号、支付金额、卖家身份等关键字段。
  4. 检查交易状态是否符合业务要求。
  5. 以幂等方式把本地订单更新为已支付。
  6. 处理成功后返回纯文本 success。

示意代码:

@PostMapping("/api/alipay/notify")
@ResponseBody
public String handleNotify(HttpServletRequest request) throws Exception {
    Map<String, String> params = extractAlipayParams(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 appIdFromNotify = params.get("app_id");

    // 还应校验 app_id、金额、商户身份等是否与本地订单一致
    if (!appId.equals(appIdFromNotify)) {
        return "failure";
    }

    if ("TRADE_SUCCESS".equals(tradeStatus)
            || "TRADE_FINISHED".equals(tradeStatus)) {
        paymentService.markPaidIdempotently(outTradeNo, totalAmount);
        return "success";
    }

    return "failure";
}

extractAlipayParams 需要根据实际使用的 Web 框架,读取请求中的全部参数。验签前不要自行删除、拼接或修改这些字段。

支付宝可能重复发送异步通知,因此更新订单时必须保证幂等。例如,订单已经处于 已支付 状态,后续收到相同通知时,不应再次发货、增加余额或生成权益。

2. 同步跳转只用于页面展示

用户完成支付后,浏览器会进入类似下面的地址:

https://www.example.com/payment/return?out_trade_no=...&trade_no=...&sign=...

同步跳转中的参数也应验签。不过,即使验签通过,也不建议直接把订单改为已支付。更稳妥的方式是使用商户订单号查询本地订单状态:

@GetMapping("/payment/return")
public String paymentReturn(
        @RequestParam("out_trade_no") String outTradeNo,
        Model model) {

    PaymentOrder order = paymentService.findByOrderNo(outTradeNo);

    model.addAttribute("orderNo", outTradeNo);
    model.addAttribute("status", order.getStatus());

    return "payment-result";
}

如果异步通知还未处理完成,页面可以先显示 支付结果确认中,再轮询业务服务器:

async function waitForPayment(orderNo) {
  const timer = setInterval(async () => {
    const response = await fetch(
      `/api/orders/${encodeURIComponent(orderNo)}/payment-status`
    );
    const result = await response.json();

    if (result.status === "PAID") {
      clearInterval(timer);
      window.location.replace(
        `/payment/success?orderNo=${encodeURIComponent(orderNo)}`
      );
    }

    if (result.status === "CLOSED" || result.status === "FAILED") {
      clearInterval(timer);
    }
  }, 2000);
}

如果服务端长时间没有收到异步通知,可以调用支付宝交易查询接口核实交易状态。前端不能直接调用需要商户私钥签名的接口,也不能把商户私钥写入 JavaScript。

推荐的完整流程

网站创建本地订单
    ↓
服务端调用 alipay.trade.page.pay,并设置 return_url、notify_url
    ↓
浏览器进入支付宝收银台
    ↓
用户完成支付
    ├─ 支付宝服务器调用 notify_url
    │      ↓
    │   服务端验签、核对金额并更新订单
    │
    └─ 浏览器跳转到 return_url
           ↓
        页面查询本地订单状态
           ↓
        展示支付成功或“确认中”

常见问题

设置了 return_url,为什么没有跳转?

浏览器跳转不是绝对可靠的。用户可能在支付后直接关闭页面,网络也可能中断,支付宝收银台的实际交互还可能受到终端环境影响。因此,业务流程不能假定用户一定会返回网站。

可以检查以下项目:

  • return_url 是否为完整的外网地址。
  • 该地址能否通过 HTTPS 正常访问。
  • 发起支付时是否确实将该地址设置到了请求对象中。
  • 页面是否存在登录拦截、循环重定向或跨域跳转限制。
  • 当前支付产品是否支持这种返回方式,参数是否符合接入文档。

可以只使用 return_url 吗?

不建议。只处理同步跳转,会漏掉用户关闭页面等情况,也容易把页面参数当成可信的支付凭证。至少应配置 notify_url,并以服务端验签后的异步通知或主动查询结果为准。

可以直接跳到固定的“支付成功”页面吗?

可以跳转,但不能因为这个页面被访问,就认定付款已经成功。成功页应携带商户订单号,并向服务端查询订单的真实状态。

订单号只能用于定位订单,不能代替身份校验。查询接口还需要确认当前用户是否有权查看该订单。

notify_url 返回 HTML 可以吗?

不应返回成功页面。异步通知是支付宝服务器与商户服务器之间的通信,处理成功后通常应返回以下纯文本:

success

浏览器页面由 return_url 负责展示,不要混用这两个地址。

备注:内容仅供参考。