小程序web-view中的B主体h5如何拉起自动续费支付?
结论
B 主体的 H5 页面无法在 A 主体小程序的 web-view 中直接以 B 主体的身份拉起微信支付自动续费。
可行的方式是让 H5 跳转到 A 小程序的原生页面,再由原生页面调用微信支付的签约能力。前提是 A 小程序的 AppID、实际收款商户号和自动续费产品已经按微信支付的要求完成绑定、授权和开通。如果 B 商户号无法与 A 小程序建立合规的支付关系,就需要通过 B 自己的小程序或公众号 H5 完成签约。
普通的 wx.requestPayment 只能用于单次支付,不能代替自动续费签约。
为什么不能直接从 H5 拉起
小程序中的 web-view 是一个受限制的网页容器,不等同于普通的微信内置浏览器。支付权限最终属于承载页面的小程序 AppID。页面内容来自 B 主体,并不会让支付身份自动切换到 B 主体。
自动续费通常涉及以下关系:
- 用户授权续费时使用的
AppID - 实际收款的微信支付商户号
- 商户已经开通的委托扣款、签约或自动续费产品
- 签约模板、扣款规则和回调地址
AppID与商户号之间的绑定或授权关系
即使 B 的后端能够创建签约请求,只要参数中的 AppID、商户号与实际调用签约能力的小程序不匹配,微信支付通常就会拒绝请求。
自动续费也不能通过网页脚本模拟为”定期调用支付”。首次开通必须由用户明确授权,后续扣款则应由服务端按照相应产品的规则执行。
推荐实现方案
方案一:在 A 小程序原生页面完成签约
该方案适用于 B 商户号可以合规使用 A 小程序 AppID,且微信支付后台允许双方建立相应关系的情况。
具体流程如下:
- B 的 H5 向 B 后端申请一次性业务凭证。
- H5 使用
wx.miniProgram.navigateTo跳转到 A 小程序的原生签约页面。 - A 小程序将业务凭证发送给服务端。
- 服务端校验用户身份、商品、金额和签约状态。
- 服务端调用已开通的微信支付自动续费或委托扣款接口,生成签约参数。
- 小程序通过该产品指定的客户端能力拉起签约页面。
- 服务端接收微信支付回调,并通过服务端查询结果确认签约状态。
- 后续续费由服务端按协议发起,不依赖 H5 或小程序持续运行。
H5 跳转示例:
<script>
function openRenewPage() {
const bizToken = '服务端生成的一次性业务凭证';
if (!window.wx || !wx.miniProgram) {
alert('请在指定的小程序中打开');
return;
}
wx.miniProgram.navigateTo({
url: `/pages/renew/index?bizToken=${encodeURIComponent(bizToken)}`,
success() {
console.log('已进入签约页面');
},
fail(error) {
console.error('跳转签约页面失败', error);
}
});
}
</script>
小程序原生页面可以先向后端换取签约参数:
Page({
async onLoad(options) {
const bizToken = options.bizToken;
if (!bizToken) {
wx.showToast({
title: '签约参数缺失',
icon: 'none'
});
return;
}
try {
const result = await this.createContract(bizToken);
await this.openContract(result);
} catch (error) {
console.error('自动续费签约失败', error);
wx.showToast({
title: '签约未完成',
icon: 'none'
});
}
},
createContract(bizToken) {
return new Promise((resolve, reject) => {
wx.request({
url: 'https://api.example.com/payment/renew/contracts',
method: 'POST',
data: { bizToken },
success(response) {
if (response.statusCode === 200 && response.data) {
resolve(response.data);
} else {
reject(new Error('创建签约请求失败'));
}
},
fail: reject
});
});
},
async openContract(contractData) {
// 此处必须调用实际开通的微信支付产品所规定的签约能力。
// 不同自动续费、委托扣款产品的客户端 API 和参数可能不同,
// 应以商户平台中该产品当前提供的接入文档为准。
throw new Error('请接入对应产品的正式签约 API');
}
});
示例没有将签约接口写成某个固定 API,因为”自动续费”可能对应不同的微信支付产品,各产品的签约入口、参数结构和准入条件并不完全相同。如果尚未明确产品名称和接入文档,就不能将 wx.requestPayment 或其他接口当作通用签约接口。
方案二:转到 B 自有的支付入口
如果 B 商户号不能绑定或授权给 A 小程序,可以让用户进入 B 自己的支付载体,例如:
- B 主体的小程序原生签约页面;
- B 主体公众号体系下符合 JSAPI 支付要求的 H5 页面;
- 微信支付为该自动续费产品提供的其他正式签约入口。
在这种方案中,A 小程序只负责业务跳转,不参与 B 的支付参数生成和签约调用。从 A 小程序跳转到 B 小程序是否被允许,以及是否需要配置关联关系,应以当前的小程序平台规则为准。
单次支付不能替代自动续费
下面的代码只能拉起一次普通的小程序支付:
wx.requestPayment({
timeStamp,
nonceStr,
package: packageValue,
signType: 'RSA',
paySign,
success() {
console.log('本次支付完成');
},
fail(error) {
console.error('本次支付未完成', error);
}
});
这段代码不能表示用户已经同意自动续费,也不能授权商户在之后自动扣款。完整流程必须包含独立签约、协议展示、用户确认、签约结果回调、后续扣款和解约能力。
关键注意事项
- 不要信任 H5 传入的金额、商户号、扣款周期或签约模板编号。H5 只应传递一次性业务凭证,真实数据需要由服务端重新查询和校验。
- 签约参数中的
AppID必须与实际拉起签约的小程序或公众号一致,不能混用 A、B 两套AppID。 - 商户号必须已经开通对应的自动续费或委托扣款产品。开通普通微信支付并不代表具备自动扣款权限。
- 不能只根据客户端的
success回调判断签约成功。最终状态应以微信支付的服务端通知或主动查询结果为准。 - 业务页面需要清楚展示服务内容、扣费金额、扣费周期、续费规则、取消方式和退款规则。
- 必须提供查询签约状态和解除自动续费的入口,并妥善处理解约、扣款失败和协议失效等情况。
- 不建议依赖
web-view的postMessage实时返回签约结果,因为它的消息触发时机有限。用户返回页面后,小程序或 H5 应根据业务单号向服务端查询最新状态。 - A、B 属于不同主体时,还需要确认收款主体、服务提供主体、用户协议和开票主体是否一致,避免技术上已经接通,却不符合平台规则或交易合规要求。
实际落地前,需要先确认申请的是哪一种微信支付产品,以及微信支付商户平台是否允许 B 商户号与 A 小程序 AppID 建立所需关系。只有确认这两点,才能确定最终使用的签约 API 和参数格式。
备注:内容仅供参考。