支付宝小程序是否支持支付宝 H5 支付,如何实现?
结论
支付宝小程序可以完成支付宝付款,但不应直接接入面向手机浏览器的“支付宝 H5 支付(手机网站支付)”。
在支付宝小程序中,一般使用以下支付流程:
- 小程序向业务服务器请求创建订单。
- 服务器调用支付宝开放平台的
alipay.trade.create。 - 服务器将支付宝返回的交易号
trade_no传给小程序。 - 小程序调用
my.tradePay拉起收银台。 - 服务器通过异步通知或主动查询确认最终支付结果。
如果业务页面是通过 <web-view> 加载的 H5 页面,也建议由 H5 通知小程序原生页面,再调用 my.tradePay 发起支付,不要直接在 <web-view> 中使用手机网站支付链接。
为什么不能直接套用 H5 支付
支付宝 H5 支付一般指手机网站支付,典型接口是 alipay.trade.wap.pay。该接口面向普通移动浏览器,通过页面跳转进入支付宝收银台。
支付宝小程序运行在独立的小程序容器中,有自己的支付能力和调用规范。直接在小程序或 <web-view> 中打开 H5 支付地址,可能出现以下问题:
- 无法正常跳转,或者支付后无法返回小程序。
<web-view>的域名和页面跳转会受到安全策略限制。- 如果仅根据前端跳转判断支付结果,很容易误判。
- 平台审核要求可能与支付产品权限不匹配。
- 小程序原生收银台通常更加稳定。
所以,即使现有业务已经接入 alipay.trade.wap.pay,也建议为支付宝小程序增加单独的支付入口。
推荐实现流程
1. 开通并配置支付能力
先在支付宝开放平台完成相关配置:
- 创建并配置支付宝小程序。
- 为应用申请可用的支付能力。
- 配置应用公钥或支付宝公钥证书。
- 设置支付异步通知地址。
- 确认小程序主体、商户账户和支付产品符合平台要求。
开放平台可能调整产品名称和签约条件,具体内容应以当前支付宝开放平台控制台和官方文档为准。
2. 小程序请求业务服务器创建订单
小程序不能直接调用支付宝服务端接口,也不能把应用私钥写入小程序代码。
my.request({
url: 'https://api.example.com/pay/alipay/mini/create',
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
data: {
orderId: 'ORDER_202609090001'
},
success(res) {
if (!res.data || !res.data.tradeNO) {
my.alert({
title: '创建订单失败',
content: res.data?.message || '服务器未返回交易号'
});
return;
}
startPay(res.data.tradeNO);
},
fail() {
my.alert({
title: '请求失败',
content: '请检查网络后重试'
});
}
});
服务器应根据 orderId 查询并计算订单金额和商品信息,不能直接信任客户端提交的金额。
3. 服务器调用 alipay.trade.create
下面的代码仅用于说明流程。SDK 初始化方式和方法名称需要根据实际使用的支付宝服务端 SDK 版本调整。
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipay.com/gateway.do",
APP_ID,
APP_PRIVATE_KEY,
"json",
"UTF-8",
ALIPAY_PUBLIC_KEY,
"RSA2"
);
AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
request.setNotifyUrl("https://api.example.com/pay/alipay/notify");
AlipayTradeCreateModel model = new AlipayTradeCreateModel();
model.setOutTradeNo("ORDER_202609090001");
model.setTotalAmount("99.00");
model.setSubject("订单商品");
model.setBuyerId(alipayUserId);
request.setBizModel(model);
AlipayTradeCreateResponse response = alipayClient.execute(request);
if (!response.isSuccess()) {
throw new IllegalStateException(
response.getSubCode() + ": " + response.getSubMsg()
);
}
String tradeNo = response.getTradeNo();
这里的 buyer_id 是支付宝用户标识,不是业务系统中的用户 ID。通常需要先完成支付宝授权登录,再由服务器获取并保存对应的支付宝用户标识。
接口调用成功后,只需向小程序返回发起支付所需的信息:
{
"tradeNO": "2026090922000000000000000000"
}
4. 小程序调用 my.tradePay
function startPay(tradeNO) {
my.tradePay({
tradeNO,
success(result) {
// 前端结果只能用于交互提示,不能作为发货依据
if (result.resultCode === '9000') {
queryOrderStatus();
} else if (result.resultCode === '6001') {
my.showToast({
content: '支付已取消'
});
} else {
queryOrderStatus();
}
},
fail() {
// 调用失败不代表订单一定未支付,仍应向服务器查询
queryOrderStatus();
}
});
}
不同运行环境或基础库版本返回的字段可能不同,实际处理时应以当前 my.tradePay 文档和真机返回值为准。
5. 由服务器确认支付状态
支付成功回调、前端返回和页面跳转都有可能延迟或丢失。业务服务器应以支付宝异步通知的验签结果为准,也可以通过主动调用交易查询接口确认状态。
前端可以轮询自己的订单查询接口:
function queryOrderStatus() {
my.request({
url: 'https://api.example.com/orders/ORDER_202609090001',
method: 'GET',
success(res) {
if (res.data?.status === 'PAID') {
my.redirectTo({
url: '/pages/pay-result/pay-result?status=success'
});
} else {
my.showToast({
content: '支付结果确认中'
});
}
}
});
}
服务器收到异步通知后,需要执行以下操作:
- 验证支付宝签名。
- 校验
app_id、商户订单号和支付金额。 - 检查交易状态。
- 以幂等方式更新订单。
- 按支付宝要求返回通知响应。
H5 页面嵌入小程序时怎么处理
如果商品页或收银页面已经使用 H5,可以继续保留,但支付动作应交给小程序原生层处理。常见流程如下:
H5 点击支付
↓
H5 将业务订单号发送给小程序
↓
小程序请求服务器创建支付宝交易
↓
小程序调用 my.tradePay
↓
服务器确认支付结果
↓
小程序将结果展示给用户
H5 与 <web-view> 之间的通信 API、脚本引入方式和消息回调格式可能随小程序基础库变化,应按照当前支付宝小程序 <web-view> 官方文档实现。H5 只需传递业务订单号,服务器应重新核验订单,不能直接使用 H5 传来的金额创建交易。
如果现有 H5 页面还需要在普通浏览器中运行,可以由服务器区分渠道:
- 普通移动浏览器:使用
alipay.trade.wap.pay。 - 支付宝小程序:使用
alipay.trade.create配合my.tradePay。
注意事项
- 应用私钥只能保存在服务器端,不能写入小程序或 H5。
- 商户订单号必须唯一。收到重复请求时,应返回同一订单状态,避免重复创建交易。
- 不能根据
my.tradePay的前端回调直接发货。 - 异步通知必须验签,并校验订单金额和商户身份。
- 用户取消、网络中断或关闭收银台,并不代表订单一定未支付。
- 开发工具中的支付行为可能与真机不同,支付流程应使用真实设备验证。
- 正式环境和沙箱环境的网关、应用配置及密钥不能混用。
- 如果支付接口提示权限、买家身份或产品未签约,应先检查开放平台的能力配置,不要反复修改前端代码。
需要实现的是“小程序支付”,而不是把现有 H5 支付页面原样搬进支付宝小程序。对应的组合是服务端 alipay.trade.create 加小程序端 my.tradePay。
备注:内容仅供参考。
