H5 如何唤醒支付宝签约支付功能?
明确结论
普通 H5 页面不能直接唤起支付宝签约支付页面,也不应依赖 alipays:// 等私有跳转协议规避限制。
爱奇艺采用的流程更可能是:二维码指向支付宝认可的业务入口。用户使用支付宝扫码后,进入支付宝小程序、生活号页面,或由签约产品授权的收银台页面,再从该入口发起签约。这个过程看起来像是“H5 唤醒签约支付”,但真正发起签约的通常不是任意外部 H5。
仅凭扫码后的跳转现象,无法判断具体使用了哪种入口。还需要查看二维码的原始内容、落地页地址,以及支付宝客户端显示的页面类型。
为什么普通 H5 无法直接实现
签约支付通常涉及免密代扣、周期扣款等能力,风险高于一次性支付。支付宝会校验多项条件,包括:
- 商户是否已申请并开通对应的签约产品;
- 当前应用是否绑定该产品;
- 签约请求是否由服务端正确签名;
app_id、商户主体、产品码和签约场景是否匹配;- 当前入口是否属于产品允许的访问渠道;
- 签约页面是否由支付宝官方收银台承载。
因此,在浏览器中运行的任意 H5,不能只靠 JavaScript 调用或 URL Scheme 打开签约页面。即使某个 Scheme 能在特定支付宝版本中完成跳转,也不代表它可以用于正式生产,还可能受到白名单、客户端版本和安全策略的限制。
爱奇艺可能采用的实现方式
常见的实现方式有以下几种。
1. 二维码直接指向支付宝小程序
二维码可能是支付宝小程序码,也可能是支付宝能够识别的小程序跳转链接。用户使用支付宝扫码后,先进入爱奇艺小程序,再由小程序调用已获得授权的签约能力。
在这种流程中,H5 只负责展示活动或生成二维码,不直接发起签约。
2. 二维码指向支付宝官方签约收银台
商户服务端调用签约接口,生成由支付宝托管的签约页面或跳转表单,然后将对应地址转换成二维码。用户使用支付宝扫码后,在支付宝客户端内完成签约。
不同签约产品允许的接入渠道并不完全相同。能否采用这种方式,要以商户实际开通产品的接入文档和支付宝开放平台配置为准。
3. 使用生活号或支付宝内的授权业务入口
大型平台可能已经接入生活号、会员签约或自动续费等产品。用户扫码后先进入支付宝内部页面,再跳转到签约收银台。
这也不是“任意 H5 唤醒”,而是支付宝客户端内受控页面之间的跳转。
4. 特定产品或白名单能力
爱奇艺这类平台可能接入了特定行业产品,也可能拥有不同于普通开放平台商户的产品权限。外部人员无法只通过页面地址确认其接口权限,也不能据此认定同一协议会向所有商户开放。
推荐的实现方案
第一步:确认具体业务类型
先确定业务需要哪种能力:
- 单次支付;
- 免密代扣;
- 周期扣款;
- 自动续费;
- 会员连续包月;
- 其他协议签约。
这些业务对应的产品、接口和审核要求可能不同。不要先寻找跳转协议,再反推应该接入哪个产品。
第二步:在开放平台申请相应产品
在支付宝开放平台确认应用是否已经开通相应的签约或代扣产品,并检查:
- 应用
app_id; - 商户主体;
- 签约产品权限;
- 支持的接入渠道;
- 应用公钥及支付宝公钥;
- 签约通知地址;
- 代扣场景及经营类目。
如果控制台中没有对应产品,或者文档明确说明不支持 H5,就不能通过拼接 URL 补足这项能力。
第三步:由服务端创建签约请求
签约参数和商户签名必须由服务端生成,不能将应用私钥放入 H5 或小程序代码。
部分签约产品可能会使用 alipay.user.agreement.page.sign 一类页面签约接口,但具体接口名称和可用参数必须以当前已开通产品的官方文档为准。接口存在,并不代表当前商户一定有调用权限。
下面只展示服务端组织签约请求的基本结构。具体产品码、渠道参数和 SDK 方法需要根据开放平台文档填写:
AlipayClient alipayClient = new DefaultAlipayClient(
gatewayUrl,
appId,
merchantPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
AlipayUserAgreementPageSignRequest request =
new AlipayUserAgreementPageSignRequest();
request.setNotifyUrl(notifyUrl);
request.setReturnUrl(returnUrl);
AlipayUserAgreementPageSignModel model =
new AlipayUserAgreementPageSignModel();
model.setExternalAgreementNo(externalAgreementNo);
model.setSignScene(signScene);
model.setProductCode(productCode);
model.setPersonalProductCode(personalProductCode);
// 其他必填参数应按照实际产品文档设置
request.setBizModel(model);
String form = alipayClient.pageExecute(request).getBody();
这里的 productCode、personalProductCode 和 signScene 不能直接照搬其他商户的配置。参数必须与商户已经开通的产品一致,否则可能出现无权限、产品不匹配或签约场景无效等错误。
第四步:选择官方支持的承载入口
如果产品不支持普通 H5,可以采用以下流程:
外部 H5
↓
展示支付宝小程序码或签约二维码
↓
用户使用支付宝扫码
↓
进入支付宝小程序或官方业务页面
↓
服务端创建签约请求
↓
支付宝官方签约收银台
↓
异步通知服务端
如果业务必须从手机浏览器开始,H5 可以提示用户使用支付宝扫码,或者引导用户进入支付宝小程序。能否从浏览器直接跳转,要以该产品公开说明的接入方式为准。
第五步:以异步通知确认签约结果
用户返回页面、关闭页面或看到“签约成功”提示,都不能作为最终的签约依据。服务端应验证支付宝异步通知的签名,并保存:
- 商户签约号;
- 支付宝协议号;
- 签约状态;
- 签约时间;
- 解约状态;
- 用户与业务账号的绑定关系。
示意代码如下:
Map<String, String> params = getRequestParameters(request);
boolean verified = AlipaySignature.rsaCheckV1(
params,
alipayPublicKey,
"UTF-8",
"RSA2"
);
if (!verified) {
response.setStatus(400);
return;
}
String externalAgreementNo = params.get("external_agreement_no");
String agreementNo = params.get("agreement_no");
String status = params.get("status");
// 根据实际通知字段及官方文档更新签约状态
updateAgreement(externalAgreementNo, agreementNo, status);
response.getWriter().write("success");
通知字段应以实际接口文档为准。上述代码只用于说明验签和落库流程,不表示所有签约产品都会返回完全相同的字段。
如何判断二维码实际打开了什么
可以先识别二维码中的原始内容:
- 如果是普通
https://地址,可能指向 H5 中转页或官方收银台; - 如果包含小程序相关标识,通常会进入支付宝小程序;
- 如果是支付宝内部协议,可能属于客户端内部入口;
- 如果链接中带有短期令牌,通常是服务端生成的一次性或限时业务地址。
解析出 URL 并不等于获得了相应能力。链接背后仍可能校验商户身份、应用权限、签名、有效期和用户登录状态。直接复制爱奇艺的地址或参数,通常无法用于其他商户。
注意事项
- 不要在前端保存应用私钥,也不要在前端生成支付宝请求签名。
- 不要将抓包得到的内部 Scheme 当作开放接口使用。
- 不要复制其他商户的
app_id、产品码、签约号或收银台地址。 - 二维码中应避免直接放入可能被篡改的业务参数,建议使用服务端生成的短期令牌。
return_url只负责页面返回,不能代替异步通知。- 签约号应保持唯一,并对重复通知和重复提交进行幂等处理。
- 自动续费等业务还需要清楚展示扣款规则、续费价格和取消方式,并满足相应的合规要求。
- 如果开放平台文档明确说明当前产品不支持 H5,应改用支付宝小程序或官方允许的页面入口,不要通过跳转协议规避渠道限制。
爱奇艺能够完成这套流程,通常不是因为掌握了某种“H5 唤醒技巧”,而是因为它已经开通对应的签约产品,并通过支付宝认可的入口发起签约。普通商户应先确认产品权限和支持渠道,再选择小程序码、官方签约页面或其他正式接入方案。
备注:内容仅供参考。
