如何开通 H5 支付宝浏览器支付功能进行测试?
结论
在 H5 浏览器中测试支付宝支付,商家账号需要先开通“手机网站支付”产品,并在支付宝开放平台创建网页应用,配置密钥和回调地址。服务端通过 alipay.trade.wap.pay 接口生成支付表单,浏览器加载并提交表单后会跳转到支付宝收银台。
开发联调阶段可以先使用支付宝开放平台的沙箱环境。不过,沙箱测试通过不等于已经具备正式支付能力。上线前仍需完成商家签约和应用审核。
开通前的准备
开通前通常要满足以下条件:
- 支付宝商家账号已完成实名认证。
- 已在支付宝开放平台创建应用。
- 网站域名、经营内容和主体资质符合支付宝的审核要求。
- 支付请求由服务端生成并签名,应用私钥不能放在 H5 页面中。
- 已准备一个可通过公网访问的异步通知地址。
开放平台后台的菜单名称可能会调整,具体入口以当前控制台显示为准。
正式环境开通步骤
1. 创建网页应用
登录支付宝开放平台,在控制台中创建网页或移动类应用。填写应用名称、应用简介和网站地址等资料,再根据页面提示提交审核。
创建完成后可以获得应用的 app_id。
2. 添加手机网站支付能力
进入应用详情,在产品绑定或能力管理页面添加“手机网站支付”。
如果后台提示需要签约,请按页面要求补充经营类目、网站信息和相关资质。只有审核通过且签约生效,正式应用才能调用支付接口。
“电脑网站支付”和“手机网站支付”是两个不同的产品。H5 页面应使用手机网站支付对应的 alipay.trade.wap.pay 接口。
3. 配置应用密钥
建议使用支付宝开放平台提供的密钥工具生成 RSA2 密钥,然后在应用后台配置应用公钥。
服务端需要保存以下信息:
- 应用私钥:用于对支付请求签名。
- 支付宝公钥:用于验证支付宝通知签名。
app_id:用于标识当前应用。
“支付宝公钥”和“应用公钥”用途不同,不要混淆。应用私钥也不能提交到前端代码、Git 仓库或日志系统。
4. 配置回调地址
支付请求一般包含两个回调地址:
notify_url:支付宝服务器发送异步通知的地址,用于确认支付结果。return_url:用户完成支付后,浏览器返回的页面地址。
业务系统应以 notify_url 的验签结果和订单状态查询结果为准,不能只根据 return_url 判断支付是否成功。
使用沙箱进行测试
如果正式产品还没有完成签约,可以在开放平台的沙箱环境中创建沙箱应用,并获取以下信息:
app_id- 应用私钥及支付宝公钥
- 沙箱买家账号
- 沙箱网关地址
常见的沙箱网关为:
https://openapi-sandbox.dl.alipaydev.com/gateway.do
正式环境网关为:
https://openapi.alipay.com/gateway.do
网关地址和沙箱账号应以开放平台当前沙箱页面提供的信息为准。沙箱支付通常要使用支付宝提供的沙箱账号或测试客户端,普通正式账号一般不能完成全部测试流程。
服务端调用示例
以下示例使用 Java 和支付宝 SDK。具体依赖版本应根据项目环境和支付宝官方文档选择,不建议直接复制未经确认的固定版本号。
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi-sandbox.dl.alipaydev.com/gateway.do",
APP_ID,
APP_PRIVATE_KEY,
"json",
"UTF-8",
ALIPAY_PUBLIC_KEY,
"RSA2"
);
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.setNotifyUrl("https://example.com/api/alipay/notify");
request.setReturnUrl("https://example.com/pay/result");
AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
model.setOutTradeNo("ORDER_202609090001");
model.setTotalAmount("0.01");
model.setSubject("测试订单");
model.setProductCode("QUICK_WAP_WAY");
request.setBizModel(model);
AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
if (response.isSuccess()) {
String paymentForm = response.getBody();
// 将 paymentForm 作为 HTML 返回给浏览器
} else {
// 记录错误码和错误信息,注意不要输出私钥等敏感数据
}
服务端可以把 SDK 返回的表单直接输出为 HTML:
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(paymentForm);
response.getWriter().flush();
浏览器访问这个服务端接口后,页面会提交表单并进入支付宝收银台。不要通过 AJAX 获取表单后把它当作普通字符串显示。可以让浏览器直接访问支付接口,也可以把表单写入新页面后执行提交。
异步通知处理
异步通知接口至少要完成以下检查:
- 使用支付宝公钥验证通知签名。
- 检查
app_id是否属于当前应用。 - 检查
out_trade_no是否存在。 - 核对订单金额和商家信息。
- 根据
trade_status幂等更新订单。 - 处理成功后返回纯文本
success。
示意代码如下:
Map<String, String> params = getAlipayParams(request);
boolean verified = AlipaySignature.rsaCheckV1(
params,
ALIPAY_PUBLIC_KEY,
"UTF-8",
"RSA2"
);
if (!verified) {
response.getWriter().write("failure");
return;
}
String tradeStatus = params.get("trade_status");
String outTradeNo = params.get("out_trade_no");
String totalAmount = params.get("total_amount");
// 继续校验 app_id、订单金额、商家信息及本地订单状态。
// 更新订单时必须保证幂等,避免重复通知造成重复入账。
if ("TRADE_SUCCESS".equals(tradeStatus)
|| "TRADE_FINISHED".equals(tradeStatus)) {
response.getWriter().write("success");
} else {
response.getWriter().write("failure");
}
notify_url 必须能被支付宝服务器访问。本机的 localhost、局域网 IP,以及需要登录验证的地址通常都无法接收通知。开发阶段可以使用合规的公网测试环境,但不要因此暴露无关的本地服务。
常见问题
浏览器没有跳转到支付宝
检查服务端返回的内容是否为 pageExecute() 生成的完整 HTML 表单,以及页面有没有执行表单提交。同时确认跳转没有受到 CSP、iframe 限制或浏览器弹窗策略的拦截。
提示产品未签约或无权限
这通常说明应用没有添加“手机网站支付”、签约尚未生效,或者使用了错误的 app_id。沙箱应用和正式应用的配置不能混用。
提示验签失败
可以重点检查以下内容:
- 应用私钥是否与后台配置的应用公钥配对。
- 验签时使用的是否为支付宝公钥。
sign_type是否一致,通常为RSA2。- 字符集是否一致,通常为
UTF-8。 - 验签前是否修改、解码或遗漏了通知参数。
支付后页面显示成功,但订单仍未支付
return_url 只用于页面跳转,不能作为可靠的支付凭证。应先检查异步通知是否到达并通过验签,必要时再调用支付宝交易查询接口核实订单状态。
注意事项
- 金额应使用字符串表示,例如
"0.01",避免直接用浮点数计算。 out_trade_no在商家系统内必须唯一。- 切换沙箱和正式环境时,网关、应用 ID、密钥及账号必须成套切换。
- 支付接口必须部署在服务端,前端不能持有应用私钥。
- 支付宝可能重复发送异步通知,因此订单更新必须具有幂等性。
- 上线前应测试支付成功、取消支付、重复通知、金额不一致、签名错误和订单超时等场景。
- H5 页面能否直接唤起支付宝 App,取决于设备、浏览器和支付宝客户端的状态。即使没有唤起 App,也可能通过网页收银台继续完成支付。
备注:内容仅供参考。
