实际开发中有这么一个场景,基于微信公众号(服务号)支付,当前微信用户可以给自己或指定的APP用户充值:
实际的交互流程为:
第一步:用户同意授权获取code值 应用授权作用域scope参数值固定为snsapi_base(这种方式不弹出授权页面,直接跳转,只能获取用户openid) 授权URL(参考微信官方说明): 其中redirect_uri参数为授权成功后回调的地址,如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE redirect_uri地址前端去自定义一个可以GET方式接收code值的地址,把接收到的code值调用第二步传递给服务端。
第二步:前端调用服务端"根据code值查询用户openid接口" 服务端提供一个此接口来根据code值获取用户的openid值返回给前端。
第三步: 前端调用服务端提供一个类似“支付下单接口”,前端调用接口传递指定充值的用户ID值、第二步获取到的openid值、充值商品ID,服务端返回jsapi支付所需要的信息,包括:appId,sign,timestamp,nonceStr,signType等,此接口返回值参考,其中appid、partnerid参数值为随便造的,不是真实的:
{
"code": 200,
"msg": "",
"data": {
"appid": "wx86906g987d603ju8b",
"partnerid": 2025144900,
"prepayid": "wx1616032147435333b2c4b6e0a47ca20000",
"package": "Sign=WXPay",
"noncestr": "a4a9a1687229c577d403cba1f82f1540",
"timestamp": 1602835401,
"sign": "B23F8E0E57929F755BAEDD2EE4F91893"
}
}
整体交互如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>微信内H5调起支付演示</title>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
</head>
<body>
详情查看源码
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
var $_GET = (function(){
var url = window.document.location.href.toString(); //获取的完整url
var u = url.split("?");
if(typeof(u[1]) == "string"){
u = u[1].split("&");
var get = {};
for(var i in u){
var j = u[i].split("=");
get[j[0]] = j[1];
}
return get;
} else {
return {};
}
})();
function doPay(openid)
{
$.ajax({
type : "post",
url : '服务端支付下单接口',
dataType : "jsonp",
data:{ type: "WechatWapOrder", uid: 2, pid:15, openid:openid}, //业务参数
async: false,
success: function(result) {//返回的json数据
//调起支付(参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6)
//以下调起支付必须在微信手机APP内打开,否则会报:{"errMsg":"没有此SDK或暂不支持此SDK模拟"}
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":result.data.appid, //公众号名称,由商户传入
"timeStamp":result.data.timestamp, //时间戳,自1970年以来的秒数
"nonceStr":result.data.noncestr, //随机串
"package": result.data.package,
"signType":"MD5", //微信签名方式,要与服务端一致
"paySign":result.data.sign //微信签名
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ){
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
}
});
}
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
} else {
onBridgeReady();
}
}
});
}
var openid = localStorage.getItem('openid');
if (openid == null) {
var redirectUri = encodeURI('http://公从号-功能设置中的网页授权域名/wx.html'); //回调通知地址可以和当面前面是同一个,也可以不是同一个,如果是此样例中是同一个地址的话,要防止反复跳转微信授权登录
window.location.href='https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx86906g987d603ju8b&redirect_uri='+redirectUri+'&response_type=code&scope=snsapi_base&state=ligaofengtest#wechat_redirect';
var code = $_GET['code'];
if (typeof(code) != 'undefined') {
var url = 'http://服务端根据code获取openid接口/getopenid?code='+code;
$.ajax({
type : "get",
url : url,
dataType : "jsonp",
async: false,
success: function(result) { //返回的json数据
if (result.code == 200) {
var openid = result.data.openid;
localStorage.setItem("openid", openid);
doPay(openid);
}
}
});
}
} else {
doPay(openid);
}
</script>
</html>