PAYATHON 2026

如何使用 alipay.trade.page.pay 生成 GET 支付链接?

支付小周

明确结论

这里的 "get" 是指通过 HTTP GET 请求访问支付宝网关。具体做法是将 alipay.trade.page.pay 需要的公共参数、业务参数和签名放入 URL 查询字符串,再让浏览器跳转到这个 URL。

完整链接大致如下:

https://openapi.alipay.com/gateway.do?app_id=...&method=alipay.trade.page.pay&...&biz_content=...&sign=...

建议直接使用支付宝开放平台 SDK 生成 GET 跳转地址,由 SDK 处理参数排序、签名和 URL 编码。不要先对参数进行 URL 编码再签名,也不要对完整的支付链接整体执行一次 UrlEncode。

"get" 方式具体指什么

alipay.trade.page.pay 是电脑网站支付接口。调用接口后,需要将用户的浏览器引导至支付宝收银台,常见方式有两种:

  • POST:SDK 返回一段自动提交的 HTML 表单,商户页面将其输出给浏览器。
  • GET:SDK 返回一个带查询参数的支付宝网关地址,商户通过 HTTP 302 或前端跳转打开该地址。

因此,GET 方式并不是把接口调用改成普通的后端 JSON GET 请求,而是生成一个已经完成签名的收银台跳转链接。

例如:

https://openapi.alipay.com/gateway.do?app_id=2021...&method=alipay.trade.page.pay&charset=utf-8&sign_type=RSA2&timestamp=2026-09-09+10%3A00%3A00&version=1.0&biz_content=%7B...%7D&sign=...

推荐做法:通过 SDK 生成链接

以 Java SDK 为例,调用 pageExecute(request, "GET") 后读取响应内容:

import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;

public class AlipayPagePayExample {

    public static void main(String[] args) throws Exception {
        String gatewayUrl = "https://openapi.alipay.com/gateway.do";
        String appId = "你的应用APPID";
        String appPrivateKey = "你的应用私钥";
        String alipayPublicKey = "支付宝公钥";

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

        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();

        // 支付完成后的同步跳转地址
        request.setReturnUrl("https://www.example.com/alipay/return");

        // 支付结果异步通知地址
        request.setNotifyUrl("https://www.example.com/alipay/notify");

        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
        model.setOutTradeNo("ORDER_202609090001");
        model.setTotalAmount("99.00");
        model.setSubject("订单商品");
        model.setProductCode("FAST_INSTANT_TRADE_PAY");

        request.setBizModel(model);

        AlipayTradePagePayResponse response =
                alipayClient.pageExecute(request, "GET");

        String paymentUrl = response.getBody();
        System.out.println(paymentUrl);
    }
}

通常可以直接使用 response.getBody() 返回的内容进行浏览器跳转:

response.sendRedirect(paymentUrl);

上面的代码假设当前支付宝 Java SDK 提供 pageExecute(request, "GET") 重载。不同语言或不同版本的 SDK 可能使用不同的方法名称,请以实际使用的 SDK 接口为准。如果 GET 重载不可用,也可以通过 SDK 生成签名参数,但不建议自行实现签名算法。

手工拼接时的正确顺序

如果确实需要手工构造链接,应按以下顺序处理:

  1. 准备公共请求参数。
  2. 将业务参数序列化为 biz_content JSON 字符串。
  3. 排除 sign,按参数名排序并生成待签名字符串。
  4. 使用应用私钥进行 RSA2 签名。
  5. 将签名结果放入 sign 参数。
  6. 分别对每个参数名和参数值进行 UTF-8 URL 编码。
  7. 使用 & 连接参数,再拼接到支付宝网关地址后面。

示意代码如下:

Map<String, String> params = new HashMap<>();
params.put("app_id", "你的应用APPID");
params.put("method", "alipay.trade.page.pay");
params.put("format", "JSON");
params.put("charset", "UTF-8");
params.put("sign_type", "RSA2");
params.put("timestamp", "2026-09-09 10:00:00");
params.put("version", "1.0");
params.put("return_url", "https://www.example.com/alipay/return");
params.put("notify_url", "https://www.example.com/alipay/notify");
params.put(
        "biz_content",
        "{\"out_trade_no\":\"ORDER_202609090001\","
        + "\"total_amount\":\"99.00\","
        + "\"subject\":\"订单商品\","
        + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}"
);

// 应使用支付宝 SDK 的签名函数,不建议自行编写 RSA2 实现。
String sign = signWithAlipaySdk(params, appPrivateKey, "UTF-8", "RSA2");
params.put("sign", sign);

String queryString = params.entrySet()
        .stream()
        .sorted(Map.Entry.comparingByKey())
        .map(entry ->
                urlEncode(entry.getKey()) + "=" + urlEncode(entry.getValue())
        )
        .collect(Collectors.joining("&"));

String paymentUrl =
        "https://openapi.alipay.com/gateway.do?" + queryString;

URL 编码函数可以写成:

private static String urlEncode(String value) {
    return URLEncoder.encode(value, StandardCharsets.UTF_8);
}

上例中的 signWithAlipaySdk(...) 只是占位名称,并非可以直接调用的标准方法。实际项目应使用当前支付宝 SDK 提供的签名工具,以免参数过滤、字符集或 RSA2 实现差异导致验签失败。

为什么必须先签名,再做 URL 编码

签名使用的是参数原始值组成的待签名字符串。例如,原始时间参数是:

timestamp=2026-09-09 10:00:00

写入 URL 后可能变成:

timestamp=2026-09-09+10%3A00%3A00

两者的表现形式不同。签名时应使用原始参数值,生成 URL 时再进行编码。如果先编码后签名,支付宝解码收到的参数后,参与验签的内容可能与商户侧不一致,从而导致验签失败。

RSA2 签名通常还包含 +、/、= 等字符。这些字符写入 URL 时必须编码,例如:

+  -> %2B
/  -> %2F
=  -> %3D

否则,+ 可能被当作空格,导致签名内容损坏。

不要对整个链接整体编码

下面这种写法是错误的:

String encodedUrl = URLEncoder.encode(paymentUrl, StandardCharsets.UTF_8);

它会将协议、斜杠、问号和参数分隔符一起编码,结果类似:

https%3A%2F%2Fopenapi.alipay.com%2Fgateway.do%3Fapp_id%3D...

浏览器不会将其识别为正常的支付宝跳转地址。

正确方式是只编码参数名和参数值,保留 URL 的结构字符:

https://openapi.alipay.com/gateway.do?key1=value1&key2=value2

网关地址需要区分环境

正式环境通常使用:

https://openapi.alipay.com/gateway.do

沙箱环境应使用沙箱配置中指定的网关地址,同时使用沙箱应用的 app_id、应用私钥和支付宝公钥。正式环境和沙箱环境的密钥、应用编号不能混用。

注意事项

  • 优先使用支付宝 SDK 完成签名和 URL 编码,不要自行拼接签名字符串。
  • 在电脑网站支付场景中,product_code 通常为 FAST_INSTANT_TRADE_PAY。
  • out_trade_no 必须由商户生成,并在商户系统中保持唯一。
  • total_amount 应使用符合接口要求的金额字符串,不要通过浮点运算拼接金额。
  • notify_url 必须是支付宝服务器能够访问的公网地址。
  • 判断支付是否成功时,不能只依赖 return_url 的同步跳转结果。应以后端异步通知和主动查询结果为准,并对通知进行验签。
  • 不要信任前端传来的订单金额和商品信息。生成支付链接前,服务端应根据订单号重新读取订单数据。
  • GET 链接可能被记录在浏览器历史、代理日志或访问日志中,因此不要将私钥、身份证号等敏感信息放入参数。
  • 如果业务参数过多,导致 URL 过长,应改用 SDK 返回的 POST 表单方式。
  • SDK 已经生成的完整 URL 不要再次编码,也不要拆开后重复编码 biz_content 或 sign。

备注:内容仅供参考。