实际开发中有这么一个场景,基于微信公众号(服务号)支付,当前微信用户可以给自己或指定的APP用户充值:

ios app嵌入h5 微信支付成功后跳转APP 微信h5支付appid_服务端

实际的交互流程为:

第一步:用户同意授权获取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>