微信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;
    }
posted @ 2018-05-26 16:34  EndlessLearning  阅读(325)  评论(0编辑  收藏  举报