• 微信JSAPI支付


    微信公众号支付流程:首先调用【网页授权获取用户信息】接口获取用户的openid和access_token:

    一、 获取code及openid

    1.前台页面首先判断code是否存在,不存在则构造网页授权获取code的URL

     mui.ready(function () {
    
            //读取localStorage的用户信息    
            if (user != undefined) {
                user = JSON.parse(user);
                userid = user.UserId;
                var vCode = getQueryString("code");
                if (is_weixn()) {
                    orderid = getQueryString("oid");
                    amount = getQueryString("amount");
                }
                $("#h_amount").html(amount);
                if (is_weixn()) {
                    mui.ajax({
                        url: '/Payment/WXPay/getWxInfo',
                        type: 'post',
                        data: {
                            code: vCode
                        },
                        dataType: 'JSON', //服务器返回json格式数据
                        //timeout: 5000, //超时时间设置为5秒;
                        success: function (json) {
                            var res = eval('(' + json + ')'); //获取json数据
                            openid = res.openid;
                            access_token = res.access_token;
                        },
                        error: function (xhr, type, errorThrown) {
                            console.log('错误');
                            //异常处理;
                            //mui.alert('网络延时,请重新加载!', '系统提示');
                        }
                    });
                }
            } else {
              
            }
        });
    

    判断是否微信浏览器代码:

     //判断是否微信内部浏览器
        function is_weixn() {
            var ua = navigator.userAgent.toLowerCase();
            if (ua.match(/MicroMessenger/i) == "micromessenger") {
                return true;
            } else {
                return false;
            }
        }
    

    ------转到后台获取code

      /// <summary>
            /// 充值页面
            /// </summary>
            /// <returns></returns>
            public ActionResult Recharge()
            {
                if (Session["openid"] == null)
                {
                    try
                    {
                        //调用【网页授权获取用户信息】接口获取用户的openid和access_token
                        string redirurl = HttpUtility.UrlEncode("http://xxx.com/Payment/WXPay/Recharge");
                        jsp.GetOpenidAndAccessToken(redirurl);
                    }
                    catch (Exception ex)
                    {
                        //Response.Write(ex.ToString());
                        //throw;
                    }
                }
                return View();
            }
    

    网页授权用户的过程:

     public void GetOpenidAndAccessToken(string redirecturi)
            {
                if (!string.IsNullOrEmpty(HttpContext.Current.Request.QueryString["code"]))
                {
                    //获取code码,以获取openid和access_token
                    string code = HttpContext.Current.Request.QueryString["code"];
                    Log.Debug(this.GetType().ToString(), "Get code : " + code);
                    GetOpenidAndAccessTokenFromCode(code);
                }
                else
                {
                    //构造网页授权获取code的URL             
                    string redirect_uri = redirecturi;//HttpUtility.UrlEncode("http://share.chn-nbiot.com/Payment/WXPay/Recharge");
                    WxPayData data = new WxPayData();
                    data.SetValue("appid", WxPayConfig.JSAPI_APPID);
                    data.SetValue("redirect_uri", redirect_uri);
                    data.SetValue("response_type", "code");
                    data.SetValue("scope", "snsapi_base");
                    data.SetValue("state", "STATE" + "#wechat_redirect");
                    string url = "https://open.weixin.qq.com/connect/oauth2/authorize?" + data.ToUrl();
                    Log.Debug(this.GetType().ToString(), "Will Redirect to URL : " + url);
                    try
                    {
                        
                        HttpContext.Current.Session["url"] = url;                    
                        //触发微信返回code码         
                         HttpContext.Current.Response.Redirect(url);//Redirect函数会抛出ThreadAbortException异常,不用处理这个异常
                    }
                    catch (System.Threading.ThreadAbortException ex)
                    {
                    }
                }
            }
    

    解析:

    1.首先支付页面会先调用【网页授权获取用户信息】接口获取用户的openid和access_token, 如果code没有获取到,则先构造网页授权获取code的URL。

    2.HttpContext.Current.Response.Redirect(url); 就是重定向URL到微信端获取code码。获取到之后在返回到你的界面,取到code码之后,拿着code码获取openid和access_token。

    二、统一下单获得签名数据

    统一下单:

       public static WxPayData UnifiedOrder(WxPayData inputObj, int timeOut = 6)
            {
            
                inputObj.SetValue("appid", WxPayConfig.JSAPI_APPID);//公众账号ID
                inputObj.SetValue("mch_id", WxPayConfig.JSAPI_MCHID);//商户号
                inputObj.SetValue("spbill_create_ip", WxPayConfig.IP);//终端ip	  	    
                inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
                //签名
                inputObj.SetValue("sign", inputObj.MakeSign(WxPayConfig.JSAPI_KEY));
                string xml = inputObj.ToXml();
    
                var start = DateTime.Now;
                string response = HttpService.Post(xml, url, false, timeOut);
                var end = DateTime.Now;
                int timeCost = (int)((end - start).TotalMilliseconds);
                WxPayData result = new WxPayData();
                result.FromXml(response);
                return result;
            }
    

    签名的KEY要是商户对应的API秘钥,否则签名错误。

    获得统一下单结果:

       public WxPayData GetUnifiedOrderResult(string outno, decimal total_fee, string opid)
            {
                //统一下单
                WxPayData data = new WxPayData();
                data.SetValue("body", "余额充值");
                data.SetValue("attach", "test");
                data.SetValue("out_trade_no", outno);
                data.SetValue("total_fee", decimal.ToInt32(total_fee * 100).ToString());
                data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));
                data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));
                data.SetValue("goods_tag", "test");
                data.SetValue("trade_type", "JSAPI");
                data.SetValue("openid", opid);
    
                WxPayData result = WxPayApi.UnifiedOrder(data);
                if (!result.IsSet("appid") || !result.IsSet("prepay_id") || result.GetValue("prepay_id").ToString() == "")
                {
                    Log.Error(this.GetType().ToString(), "UnifiedOrder response error!");
                    // throw new WxPayException("UnifiedOrder response error!");
                }
    
                unifiedOrderResult = result;
                return result;
            }
    

    微信返回来的return_code和result_code都为SUCCESS的时候,才会正确返回数据,拿到我们想要的数据后,再进行一次签名

            WxPayData newpay = new WxPayData();
            newpay.SetValue("appId", WxPayConfig.JSAPI_APPID);
            newpay.SetValue("timeStamp", WxPayData.GetTimeStamp());
            newpay.SetValue("nonceStr", wpd.GetValue("nonce_str"));
            newpay.SetValue("package", "prepay_id=" + wpd.GetValue("prepay_id"));
            newpay.SetValue("signType", "MD5");
            newpay.SetValue("paySign", newpay.MakeSign(WxPayConfig.JSAPI_KEY)); //再次生成签名
    

    注意:时间戳是10位数字,package是固定写法prepay_id=微信返回来的prepay_id,签名方法signType是MD5。

    组合一下对象返回到前台拉起微信支付:以下是我的对象名,可自行修改。

    但appid、noncestr、timestamp、trade_type、package、signType、sign 是前台必须的字段,一个不能少!!

    
                ReturnWxpay rwpay = new ReturnWxpay
                {
                    appid = newpay.GetValue("appId").ToString(),
                    noncestr = newpay.GetValue("nonceStr").ToString(),
                    timestamp = newpay.GetValue("timeStamp").ToString(),
                    trade_type = wpd.GetValue("trade_type").ToString(),
                    package = newpay.GetValue("package").ToString(),
                    signType = newpay.GetValue("signType").ToString(),
                    sign = newpay.GetValue("paySign").ToString()
                };
    

    -----------回到前台调起支付,以下是固定写法。

    注意注意::这里的前台字段的大小写,一定要对应,跟后台有差别,不要搞错了!!
    
        function callpay() {
            if (typeof WeixinJSBridge == "undefined") {
                if (document.addEventListener) {
                    document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
                } else if (document.attachEvent) {
                    document.attachEvent('WeixinJSBridgeReady', jsApiCall);
                    document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
                }
            } else {
                jsApiCall();
            }
        }
        //调用微信JS api 支付
        function jsApiCall() {
            WeixinJSBridge.invoke('getBrandWCPayRequest', {
                "appId": paystr.appid, //公众号名称,由商户传入
                "timeStamp": paystr.timestamp, //时间戳,自1970年以来的秒数
                "nonceStr": paystr.noncestr, //随机串
                "package": paystr.package,
                "signType": paystr.signType, //微信签名方式:
                "paySign": paystr.sign //微信签名
            },
                function (res) {
                    if (res.err_msg === "get_brand_wcpay_request:cancel") {
                        mui.alert('支付异常!', '提示');
                        return false;
                    } else if (res.err_msg === "get_brand_wcpay_request:ok") {
                        window.location.href = "../../../m/PersonalCenter/wallet.html";
                        mui.alert('支付成功!', '提示');
                    }
                    return true;
                }
            );
        }
    

    如果调起支付没问题,就会有支付界面出现啦。。支付成功后有个回调函数,如果支付成功后会返回re "get_brand_wcpay_request:ok",失败会返回"get_brand_wcpay_request:cancel",可自行处理条抓页面!!

    最后附上获取code码的JS
      //获取url的参数
        function getQueryString(name) {
            var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
            var r = window.location.search.substr(1).match(reg);
            if (r != null) return unescape(r[2]);
            return null;
        }
  • 相关阅读:
    WPF基础篇之控件模板(ControlTemplate)
    WPF基础篇之移动特效
    WPF基础篇之空间布局
    00-API-Mongoose
    00-API-Vue
    博客园皮肤设置
    15-Node
    16-Vue-A
    15-MongoDB
    14-电商项目
  • 原文地址:https://www.cnblogs.com/lxyang/p/9093491.html
Copyright © 2020-2023  润新知