h5支付

支付

背景

实习项目想开展支付业务,项目是 h5 嵌入 app 的。

走 app 支付的话,如果走内购,苹果抽30%,太贵了。如果走第三方(支付宝/微信),ios 审核比较严(想尽办法让你走内购,app store 审核政策),流程麻烦,不一定能走通。于是让我试试 h5 支付能不能走通第三方。查看文档后发现,微信明确表示,H5 支付不建议在 APP 端使用,如需要在 APP 中使用微信支付,请接 APP 支付。所以这条路应该是走不通了,但是因为支付是一个很重要的业务,以后可能也会遇到,所以想记录一下查阅的资料,以便后续查阅。

还有一种方法是,h5 通过 app 提供的方法唤醒 微信/支付宝,微信/支付宝再跳转到支付页面?不知道能不能过审核。

文档

微信

https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml

支付宝

https://opendocs.alipay.com/open/204/105051

流程图

img

代码

支付宝

后端

使用 SDK

当前台点击支付按钮,开始调用支付接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public void CreatPayOrderForH5(HttpSession session, HttpServletRequest request,  HttpServletResponse response)
{
AlipayClient alipayClient = new DefaultAlipayClient(AliPayConfig.URL, AliPayConfig.APPID, AliPayConfig.RSA_PRIVATE_KEY, AliPayConfig.FORMAT, AliPayConfig.input_charset, AliPayConfig.ALIPAY_PUBLIC_KEY, AliPayConfig.sign_type); //获得初始化的AlipayClient
AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
//发起支付宝支付
//设置支付完成后的返回地址
alipayRequest.setReturnUrl("www.baidu.com");
//设置回跳和通知地址
alipayRequest.setNotifyUrl("www.google.com");
alipayRequest.setBizContent("{" +
" \"out_trade_no\":\""+订单号+"\"," +
" \"total_amount\":\""+订单金额+"\"," +
" \"subject\":\""+商品标题+"\"," +
" \"product_code\":\"QUICK_WAP_PAY\"" +
" }");
String form="";
try
{
// 调用SDK生成表单
form = alipayClient.pageExecute(alipayRequest).getBody();
}
catch (AlipayApiException e)
{
form = "err";
e.printStackTrace();
}

response.setContentType("text/html;charset=" + AliPayConfig.input_charset);
//直接将完整的表单html输出到页面
response.getWriter().write(form);
response.getWriter().flush();
response.getWriter().close();
}

/*说明:
1、AliPayConfig为常量定义文件,里面包括支付宝支付的一些常用值,如AppId,公钥、私钥等等;
2、支付接口不需要返回值,直接把支付宝生成的form输出到页面即可,from正确的话前台会开始跳转支付宝
*/
支付完成后,支付宝开始调用回调接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public String AlipayTradePayNotify(Map<String, String[]> requestParams) throws AlipayApiException
{
Map<String, String> params = new HashMap<String, String>();
for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();)
{
String name = (String)iter.next();
String[] values = (String[])requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++)
{
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
// 乱码解决,这段代码在出现乱码时使用。
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
boolean signVerified = AlipaySignature.rsaCheckV1(params, AliPayConfig.ALIPAY_PUBLIC_KEY, AliPayConfig.input_charset, AliPayConfig.sign_type);
// 调用SDK验证签名
if (signVerified)
{
//签名验证成功
response.getWriter().print("success");
//处理自己的逻辑
}
else
{
// 验证失败
response.getWriter().print("failure");
// 调试用,写文本函数记录程序运行情况是否正常
String sWord = AlipaySignature.getSignCheckContentV1(params);
AliPayConfig.logResult(sWord);
}
}

/*
说明:
1、回调接口一定要写response.getWriter().print("状态"),否则支付宝收不到返回信息会一直回调该接口
*/

前端

调接口获取表单,然后唤起支付宝
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
methods: {
async doPayAlipay() {
const res = await this.$apis.doPayAlipay({
oid: res.data, // 取到的交易订单号
url: yourBackUrl // 成功后的回调地址
})

if(res.code===1) {
// 避免时间间隙造成的用户误操作,尽管拿到数据了仍然显示loading...直到跳转到支付宝的提供的页面
this.$toast.loading({
mask: true,
message: '加载中...'
});
// 把 form 插入页面中后, submit 唤醒支付宝
const div = document.createElement('div');
div.innerHTML = res.data.form;
document.body.appendChild(div);
document.forms[0].submit();
}
}
}

微信

微信的 wap 端(手机浏览器端) 支付分为两种,微信内的公众号支付 和 微信外的 H5 支付。

公众号支付

公众号支付是用户在微信中打开商户的 H5 页面,商户在 H5 页面通过调用微信支付提供的 JSAPI 接口调起微信支付模块完成支付。

注:openid 是微信用户在公众号 appid 下的唯一用户标识(appid 不同,则获取到的 openid 就不同),可用于永久标记一个用户,同时也是微信公众号支付的必传参数。网页授权获取用户 openid 接口文档。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
methods: {
weixinPay() {
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener("WeixinJSBridgeReady",this.onBridgeReady(data),false);
} else if (document.attachEvent) {
document.attachEvent("WeixinJSBridgeReady",this.onBridgeReady(data));
document.attachEvent("onWeixinJSBridgeReady",this.onBridgeReady(data));
}
} else {
this.onBridgeReady(data);
}
},
onBridgeReady(){
WeixinJSBridge.invoke(
"getBrandWCPayRequest",
{
appId: data.appid, //公众号名称,由商户传入
timeStamp: data.timestamp, //时间戳,自1970年以来的秒数
nonceStr: data.nonce_str, //随机串
package: data.prepay_id, //订单详情扩展字符串
signType: data.signType, //微信签名方式:
paySign: data.paySign, //微信签名
},
res => {
if(res.err_msg == "get_brand_wcpay_request:ok"){
// ...
}else{
alert("支付失败!");
}
}
);
}
}

微信外支付

H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前述页面确认使用微信支付时,商户发起本服务呼起微信客户端进行支付。主要用于触屏版的手机浏览器请求微信支付的场景。可以方便的从外部浏览器唤起微信支付。
注意:H5 支付不建议在 APP 端使用,如需要在 APP 中使用微信支付,请接 APP 支付。

后端通过拿到的参数请求微信后台去生成订单并同时返给前端一个路径 mweb_url,这个路径就是用来调起微信应用发起支付操作的。

1
2
3
4
5
6
7
8
9
methods: {
async doPaySubmit() {
const res = await this.$apis.doWechatPay({ oid: '', trade_type: 'MWEB'})
if(res.code===1){

window.location.replace(res.data.mweb_url+'&redirect_url='+encodeURIComponent(window.location.href+'&tip=yes'))
}
}
}

参考

https://juejin.cn/post/6859378614488530957

https://blog.csdn.net/zcl_666/article/details/75655530

https://zhuanlan.zhihu.com/p/371738453


h5支付
http://example.com/2022/11/09/h5支付/
Author
John Doe
Posted on
November 9, 2022
Licensed under