如何通过 HTTP 打开 alipay.trade.app.pay 支付签约页面
结论
alipay.trade.app.pay 不能像普通 HTTP 页面一样直接在浏览器中打开。它返回的是支付宝 App SDK 所需的订单字符串,不是收银台 URL。即使把完整的网关请求拼成链接,再转成短链或二维码,也无法代替 App SDK 的调起流程。
如果要让用户扫码进入支付宝付款,并同时签约商家扣款,需要按场景选择接口:
- 手机浏览器收银台:使用
alipay.trade.wap.pay,由服务端生成支付宝表单并完成跳转。 - 电脑网页收银台:使用
alipay.trade.page.pay。 - 纯二维码当面付:使用
alipay.trade.precreate获取qr_code。该接口通常用于扫码支付,并不意味着支持同时签约扣款。 - 当前产品不支持在 WAP/Page 支付中传入签约参数:先通过
alipay.user.agreement.page.sign完成签约,再发起支付。
能否通过 alipay.trade.wap.pay 或 alipay.trade.page.pay 一次完成支付和签约,取决于商户开通的扣款产品、签约场景,以及对应接口是否支持 agreement_sign_params。alipay.trade.app.pay 支持该字段,不代表其他支付接口也支持。
为什么当前链接不能直接使用
alipay.trade.app.pay 的标准调用流程如下:
商户服务端生成并签名 orderString
↓
商户服务端将 orderString 返回给 App
↓
App 调用支付宝客户端 SDK
↓
支付宝 App 展示支付/签约页面
生成的内容一般类似:
app_id=...&biz_content=...&charset=utf-8&method=alipay.trade.app.pay&sign=...&sign_type=RSA2×tamp=...&version=1.0
这是一组 SDK 调用参数,不是浏览器页面地址。直接访问下面这样的地址:
https://openapi-sandbox.dl.alipaydev.com/gateway.do?...
只是在向开放平台网关提交 API 请求,不会自动得到适合浏览器展示的 App 支付页面。短链服务只能缩短 URL,不能改变接口本身的调用方式。
推荐方案一:使用 WAP 支付作为扫码落地页
如果客户使用手机扫码,可以让二维码指向商户自己的 HTTPS 地址:
https://pay.example.com/order/123
用户访问该地址后,商户服务端创建 alipay.trade.wap.pay 请求,并把支付宝返回的 HTML 表单直接输出给浏览器。浏览器随后会跳转到支付宝收银台。
Java 示例:
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi-sandbox.dl.alipaydev.com/gateway.do",
appId,
merchantPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.setReturnUrl("https://pay.example.com/alipay/return");
request.setNotifyUrl("https://pay.example.com/alipay/notify");
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", "ORDER_20260909_001");
bizContent.put("subject", "test");
bizContent.put("total_amount", "0.01");
bizContent.put("product_code", "QUICK_WAP_WAY");
request.setBizContent(bizContent.toJSONString());
AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
if (!response.isSuccess()) {
throw new IllegalStateException(
response.getCode() + ": " + response.getSubMsg()
);
}
// 将 response.getBody() 作为 text/html 返回给手机浏览器。
String paymentHtml = response.getBody();
控制器应以 HTML 类型返回内容,例如:
@GetMapping(
value = "/order/{orderNo}",
produces = MediaType.TEXT_HTML_VALUE
)
@ResponseBody
public String pay(@PathVariable String orderNo) throws Exception {
return createAlipayWapPayForm(orderNo);
}
二维码中只需放入商户落地页 URL,不要直接写入包含签名和业务参数的支付宝网关请求。通过商户落地页,服务端也能检查订单状态、重新生成请求并阻止重复付款。
如何加入签约参数
只有同时满足以下条件,才可以尝试在支付请求中加入 agreement_sign_params:
- 商户已经开通对应的商家扣款产品。
- 当前签约场景和
personal_product_code已由支付宝侧配置或认可。 - 所选支付接口的当前文档明确支持
agreement_sign_params。 - 沙盒环境支持正在测试的产品和场景。
数据结构示例如下:
{
"out_trade_no": "ORDER_20260909_001",
"subject": "test",
"total_amount": "0.01",
"product_code": "QUICK_WAP_WAY",
"agreement_sign_params": {
"product_code": "GENERAL_WITHHOLDING",
"personal_product_code": "实际开通的产品码",
"sign_scene": "实际配置的签约场景",
"access_params": {
"channel": "QRCODE"
},
"period_rule_params": {
"period_type": "DAY",
"period": 1,
"execute_time": "实际有效日期",
"single_amount": "0.01",
"total_amount": "0.10",
"total_payments": 2
}
}
}
这段示例只说明数据结构,不能证明 alipay.trade.wap.pay 一定接受这些字段。具体应以商户后台已开通产品对应的最新接口文档为准。如果 WAP/Page 接口文档没有列出 agreement_sign_params,就不要自行添加。网关可能忽略该字段,也可能直接返回参数错误。
推荐方案二:拆分为“先签约,后支付”
如果当前扣款产品只支持独立签约,可以采用下面的流程:
用户扫描商户二维码
↓
打开商户签约落地页
↓
服务端调用 alipay.user.agreement.page.sign
↓
用户在支付宝完成签约
↓
商户接收并验证异步通知
↓
确认协议状态有效
↓
发起 alipay.trade.wap.pay 或其他支付流程
独立签约所需字段会因产品类型而异,通常包括:
personal_product_code
sign_scene
external_agreement_no
access_params
period_rule_params
sign_notify_url
签约成功后,需要保存支付宝返回的协议号和协议状态。后续商家扣款必须使用产品规定的扣款接口及协议标识。首次签约成功不等于后续扣款授权流程已经全部完成。
如果业务必须让用户一次确认便同时完成支付和签约,需要先确认申请的产品是否提供“支付并签约”能力,以及该能力支持哪些支付渠道。没有对应产品权限时,更换参数或拼接 URL 都无法实现这一流程。
如果只需要扫码支付
如果业务不要求在同一页面完成扣款签约,可以调用 alipay.trade.precreate。接口调用成功后会返回二维码内容:
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
request.setNotifyUrl("https://pay.example.com/alipay/notify");
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", "ORDER_20260909_002");
bizContent.put("subject", "test");
bizContent.put("total_amount", "0.01");
request.setBizContent(bizContent.toJSONString());
AlipayTradePrecreateResponse response = alipayClient.execute(request);
if (!response.isSuccess()) {
throw new IllegalStateException(
response.getCode() + ": " + response.getSubMsg()
);
}
String qrCodeContent = response.getQrCode();
应使用返回的 qrCodeContent 生成二维码,不要自行拼装网关地址。至于 alipay.trade.precreate 能否与某种签约产品组合使用,仍要以该产品的开放能力说明为准。
当前参数还需要检查的问题
当前示例还有几处可能导致报错:
- JSON 使用了单引号。实际传给接口的
biz_content必须是合法 JSON,属性名和字符串都要使用双引号。 execute_time是2024-02-06,已经过期。周期扣款规则通常要求填写符合产品约束的有效执行日期。sign_notify_url的值末尾似乎有空格:"xxx "。需要清理空格,并替换成可从公网访问的 HTTPS 地址。personal_product_code不能随意填写为auto_123,必须使用商户实际开通并配置的产品码。sign_scene必须与申请产品时配置的签约场景一致。out_trade_no应在商户系统内保持唯一,不建议长期使用固定值123。- 金额字段建议使用字符串,例如
"0.01",避免浮点数序列化带来的精度问题。 return_url只是同步跳转地址。订单和协议状态必须以验签后的异步通知或主动查询结果为准。- 沙盒不一定覆盖所有商家扣款产品。如果参数正确,但持续出现产品未开通、场景不支持或权限不足等提示,需要到正式应用中确认对应产品能力,不能直接据此判断生产环境也不可用。
在二维码浏览器场景中,优先使用“商户落地页 + alipay.trade.wap.pay”。如果该支付接口不支持当前扣款产品的一次性支付签约,就通过 alipay.user.agreement.page.sign 独立签约,再进入支付流程。alipay.trade.app.pay 则应留给已经集成支付宝客户端 SDK 的原生 App。
备注:内容仅供参考。
