18 又交新一年

图片 1

当我前的几乎篇博客,有介绍了微信支付、微信红包、企业会等各种与支出有关的操作,不过者还是依据微信一般API的包裹,本篇随笔继续微信支付即时无异主题,继续介绍因微信网页JSAPI的方式倡导的微信支付功能实现,微信的JSAPI相对于普通的API操作,调试没有那么好,而且有时小错误需要频繁核实。本篇随笔基于实际的微信网页支付案例,对微信JSAPI的支出实现进行介绍。

定开始的2018,各大电视台的跨年晚会争相表演,娱乐八卦吧当不断更新,永远不见面掉之各种谈资。

1、微信JS-SDK的知识

于本人前《C#支出微信门户及下(39)–使用微信JSSDK实现签到的功效》介绍的情节之中,有介绍了不少JS-SDK的基础知识,我们根据网页发起的微信支付,我们也是根据JS-SDK的基本功及进展发起的,因此要了解这些JS-SDK的使用手续。

相似的话,我们网页JSAPI发起的微信支付,需要以wx.chooseWXPay的操作方法,而此点子吧是得以做到wx.config初始化的下,由界面元素进行接触处理的。

譬如我们可以这样实现所有微信支付的处理过程:

1)先采取JS对API进行初始化配置

    wx.config({
        debug: false,
        appId: appid, // 必填,公众号的唯一标识
        timestamp: timestamp, // 必填,生成签名的时间戳
        nonceStr: noncestr, // 必填,生成签名的随机串
        signature: signature, // 必填,签名,见附录1
        jsApiList: [
           'checkJsApi',
           'chooseWXPay',
           'hideOptionMenu'
        ]
    });

 

2)使用wx.chooseWXPay发起微信支付

wx.chooseWXPay({
    timestamp: 0, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
    nonceStr: '', // 支付签名随机串,不长于 32 位
    package: '', // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
    signType: '', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
    paySign: '', // 支付签名
    success: function (res) {
        // 支付成功后的回调函数
    }
});

备注:prepay_id 通过微信支付合下单接口拿到,paySign
采用统一的微信支付 Sign 签名生成方法,注意这里 appId 也要是介入签署,appId
与 config 中传来的 appId 一致,即最后与签署的参数有appId, timeStamp,
nonceStr, package, signType。

 

3)获取用户的openid

当有JSAPI操作中,有时候需要传入当前用户之openid,由于是价,一般是不可知直接得到的,但好经过用户授权代码获取,因此我们得在菜单中配备好重定向的URL,根据URL获取相应的code,然后解析code为对应之openid即可。

经过code换取的是一个出奇之网页授权access_token,与功底支撑着之access_token(该access_token用于调用其他接口)不同。公众号只是经下述接口来获得网页授权access_token。如果网页授权的作用域为snsapi_base,则随步骤中收获到网页授权access_token的又,也取到了openid,snsapi_base式的网页授权流程便到之结束。

获取code后,请求以下链接获取access_token: 
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

 

同一到跨年时刻就是会专程快的则,今年的爱人围微博还在晒18岁的像,开始并未将明白其中缘由,还惦记在17年之时段也少晒17东的照。

2、微信支付JSAPI初始化的参数处理

若得到相关的JS-SDK的相干接口参数,我们用先生成JSAPI-Ticket凭证,生成是证代码接口实现如下所示。一般的话,这个接口的数额要缓存起来的,具体可以协调实现拍卖。

        /// <summary>
        /// 获取JSAPI_TICKET接口
        /// </summary>
        /// <param name="accessToken">调用接口凭证</param>
        /// <returns></returns>
        public string GetJSAPI_Ticket(string accessToken)
        {
            var url = string.Format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi", accessToken);
            var result = JsonHelper<GetTicketResult>.ConvertJson(url);
            return result != null ? result.ticket : null;
        }

咱们要贯彻JSSDK签名的处理,必须先行根据几独变量,构建好URL字符串,具体的处理过程,我们可以把它逐一放在一个Hashtable里面,如下代码所示。

        /// <summary>
        /// 获取JSSDK所需要的参数信息,返回Hashtable结合
        /// </summary>
        /// <param name="appId">微信AppID</param>
        /// <param name="jsTicket">根据Token获取到的JSSDK ticket</param>
        /// <param name="url">页面URL</param>
        /// <returns></returns>
        public static Hashtable GetParameters(string appId, string jsTicket, string url)
        {
            string timestamp = GetTimeStamp();
            string nonceStr = GetNonceStr();

            // 这里参数的顺序要按照 key 值 ASCII 码升序排序  
            string rawstring = "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "&timestamp=" + timestamp + "&url=" + url + "";

            string signature = GetSignature(rawstring);
            Hashtable signPackage = new Hashtable();
            signPackage.Add("appid", appId);
            signPackage.Add("noncestr", nonceStr);
            signPackage.Add("timestamp", timestamp);
            signPackage.Add("url", url);
            signPackage.Add("signature", signature);
            signPackage.Add("jsapi_ticket", jsTicket);
            signPackage.Add("rawstring", rawstring);

            return signPackage;
        }

这般把其位于哈希表里面,方便我们领到出用。

    wx.config({
        debug: false,
        appId: appid, // 必填,公众号的唯一标识
        timestamp: timestamp, // 必填,生成签名的时间戳
        nonceStr: noncestr, // 必填,生成签名的随机串
        signature: signature, // 必填,签名,见附录1
        jsApiList: [
           'checkJsApi',
           'chooseWXPay',
           'hideOptionMenu'
        ]
    });

为在MVC视图页面中,设置我们计算出来的价,一般我们需要在后台进行测算好,并把其在ViewBag变量中便足以当页面前端采用了,如下所示是MVC视图页面的后台代码。

        /// <summary>
        /// 刷新JS-SDK的票据
        /// </summary>
        protected virtual void RefreshTicket(AccountInfo accountInfo)
        {
            Hashtable ht = baseApi.GetJSAPI_Parameters(accountInfo.AppID, accountInfo.AppSecret, Request.Url.AbsoluteUri);
            ViewBag.appid = ht["appid"].ToString();
            ViewBag.nonceStr = ht["noncestr"].ToString();
            ViewBag.timestamp = ht["timestamp"].ToString();
            ViewBag.signature = ht["signature"].ToString();
        }

如此这般,在MVC的视图页面中,我们的代码可以这么实现JSAPI变量的初始化。

    <script language="javascript">
    var openid = '@ViewBag.openid';
    var appid = '@ViewBag.appid';
    var noncestr = '@ViewBag.noncestr';
    var signature = '@ViewBag.signature';
    var timestamp = '@ViewBag.timestamp';

    wx.config({
        debug: false,
        appId: appid, // 必填,公众号的唯一标识
        timestamp: timestamp, // 必填,生成签名的时间戳
        nonceStr: noncestr, // 必填,生成签名的随机串
        signature: signature, // 必填,签名,见附录1
        jsApiList: [
           'checkJsApi',
           'chooseWXPay',
           'hideOptionMenu'
        ]
    });

 

虽然没同台进入晒照大队,但也想起了产17/18底那段日子。庆幸当时自己并不曾遇上杀马特的大潮,虽然这懵而天真。

3、微信支付JSAPI发起微信支付的参数处理

以首先稍稍节中,我干了,初始化JS-API后,还需利用wx.chooseWXPay发起微信支付,这个接口也时有发生几乎个有关的参数。

wx.chooseWXPay({
    timestamp: 0, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
    nonceStr: '', // 支付签名随机串,不长于 32 位
    package: '', // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
    signType: '', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
    paySign: '', // 支付签名
    success: function (res) {
        // 支付成功后的回调函数
    }
});

个中这里的timestamp和nonceStr的平整与前边初始化操作的参数规则平等,但是注意不能够与初始化接口的timestamp和nonceStr保持同样,否则发起支付会冒出【 开发验证签名失败】的错误。

package的变量就是咱们调用统一下单接口的取的预下单id,格式如下所示:

prepay_id=wx2016051517463160322779de0375788970

而以取得这预下单的ID,我们先行用依据联合下单接口的要,构建一个数目对象,如下所示。

                PayOrderData data = new PayOrderData()
                {
                    product_id = id,
                    body = "测试支付" + id,
                    attach = "爱奇迪技术支持",
                    detail = "测试JSAPI支付" + id,
                    total_fee = 1,
                    goods_tag = "test" + id,
                    trade_type = "JSAPI",
                    openid = openid
                };

下一场调用前面封装了之联结下单接口API获取相应的联下单ID

                TenPayApi api = new TenPayApi(accountInfo);
                var orderResult = api.UnifiedOrder(data);
                LogHelper.Debug(string.Format("统一下单结果:{0}", (orderResult != null) ? orderResult.ToJson() : "为空值"));

                if (string.IsNullOrEmpty(orderResult.prepay_id) || string.IsNullOrEmpty(orderResult.appid))
                {
                    throw new WeixinException("统一下单结果返回失败!");
                }

signType固定为MD5,

末了剩余paySign这个比较复杂的参数了,这个参数就是要依据前这些参数进行签字的价值。微信支付的签署还是与一般性API的做法(在眼前介绍微信支付的时光,有介绍过相关的平整,具体可望《C#付出微信门户及采取(32)–微信支付接入和API封装使用》),引入实体类 WxPayData 来囤积一些工作参数,以及贯彻参数的签名处理。

值得注意的是,使用普通API的签为Sign,而采取JSAPI的签约变量名称也paySign,两者处理逻辑一样,只是称不同。

这么我们当后台处理有关的变量的代码如下所示。

        /// <summary>
        /// 获取JSAPI方式的微信字符串参数对象
        /// </summary>
        /// <param name="accountInfo">当前账号</param>
        /// <param name="prepay_id">统一下单ID</param>
        /// <returns></returns>
        private WxPayData GetJSPayParam(AccountInfo accountInfo, string prepay_id)
        {
            WxPayData data = new WxPayData();
            data.SetValue("appId", ViewBag.appId);
            data.SetValue("timeStamp", data.GenerateTimeStamp());
            data.SetValue("nonceStr", data.GenerateNonceStr());
            data.SetValue("signType", "MD5");
            data.SetValue("package", string.Format("prepay_id={0}", prepay_id));

            data.SetValue("paySign", data.MakeSign(accountInfo.PayAPIKey));//签名
            return data;
        }

然后,再定义一个控制器接口,返回相关的参数数据,部分逻辑代码如下所示。这样方便前端通过JSON的格式获取相应之变量值。

                //支付需要的参数
                WxPayData param = GetJSPayParam(accountInfo, orderResult.prepay_id);
                LogHelper.Debug("GetJSPayParam:" + param.ToJson());

                var obj = new
                {
                    timeStamp = param.GetString("timeStamp"),
                    nonceStr = param.GetString("nonceStr"),
                    signType = param.GetString("signType"),
                    package = param.GetString("package"),
                    paySign = param.GetString("paySign")
                };
                return Content(obj.ToJson());

每当面前页面,通过ajax方式取发起微信支付的相关参数,代码如下所示。

    //发起一个微信支付
    function chooseWXPay(id) {
        //alert(window.location.href);
        var uid = getUrlVars()["uid"];
        $.ajax({
            type: 'POST',
            url: '/JSSDKTest/GetWXPayData',
            //async: false, //同步
            dataType: 'json',
            data : {
                id: id,
                uid: uid,
                openid : openid
            },
            success: function (json) {
                wx.chooseWXPay({
                    appId: appid,
                    timestamp: json.timeStamp,  // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
                    nonceStr: json.nonceStr,    // 支付签名随机串,不长于 32 位
                    package: json.package,      // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
                    signType: json.signType,    // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
                    paySign: json.paySign,      // 支付签名
                    success: function (res) {   // 支付成功后的回调函数
                        if (res.errMsg == 'chooseWXPay:ok') {
                            $.toast('支付成功');
                            //setTimeout(function () {
                            //    window.location.href = "/";//这里默认跳转到主页
                            //}, 2000);
                            //window.location.href = "/Pay/order_details?orderId=" + $("#orderId").val();
                        } else if (res.errMsg == 'chooseWXPay:cancel' || res.errMsg == 'chooseWXPay:fail') {
                            $.toast("支付失败");
                            //window.location.href = "/Pay/order_details?orderId=" + $("#orderId").val();
                        }                        
                    },
                    cancel: function () {
                        $.toast("用户取消了支付");
                        //window.location.href = "/Pay/order_details?orderId=" + $("#orderId").val();
                    }
                });
                wx.error(function (res) {
                    $.toast("调用支付出现异常");
                    //window.location.href = "/Pay/order_details?orderId=" + $("#orderId").val();
                })
            },
            error: function (xhr, status, error) {
                $.toast("操作失败" + xhr.responseText); //xhr.responseText
            }
        });
    };

 

入冬以来还无真正下了相同场雪,却总感觉今年底冬特地冷,12月回了回老家与老哥的婚礼,捧了转茶领了转红包。

4、微信支付JSAPI发起微信支付的界面效果

经上面的代码,我们好顺发起微信支付,并可见到实际的测试结果了,读者可关心我们的万众号【广州爱奇迪】对里面微信支付进行测试了解。

图片 2  图片 3  图片 4

图片 5 图片 6  图片 7

微信支付成功后,我们同可在微信支付的对话里面看到响应的结果了。

图片 8

 

假若对是《C#支付微信门户及使用》系列感兴趣,可以关注自身的外文章,系列随笔如下所示:

C#出微信门户及用(40)–使用微信JSAPI实现微信支付功能

C#支付微信门户及动(39)–使用微信JSSDK实现签到的机能

C#付出微信门户及采取(38)–微信摇一摆红包功能

C#出微信门户及利用(37)–微信公众号标签管理作用

C#支付微信门户及用(36)–微信卡劵管理之包裹操作

C#付出微信门户及动(35)–微信支付的局会封装操作

C#出微信门户及采取(34)–微信裂变红包

C#支付微信门户及应用(33)–微信现金红包的包及利用

C#开发微信门户及运用(32)–微信支付接入和API封装使用

C#开微信门户及以(31)–微信语义理解接口的实现同处理

C#付出微信门户及采取(30)–信之群发处理同预览功能

C#出微信门户及利用(28)–微信“摇一摇·周边”功能的利用及接口的贯彻

C#支出微信门户及以(27)-公众号模板消息管理 

C#开发微信门户及下(26)-公众号微信资料管理

C#支付微信门户及使用(25)-微信企业号的客户端管住功能

C#付出微信门户及运用(24)-微信小店货架信息保管

C#出微信门户及以(23)-微信小店商品管理接口的包装和测试

C#支出微信门户及下(22)-微信小店的开支与以

C#开发微信门户及应用(21)-微信企业号的音以及波之收受处理与解密 

C#支付微信门户及用(20)-微信企业号的菜单管理

C#开发微信门户及下(19)-微信企业号的音发送(文本、图片、文件、语音、视频、图文信息等)

C#支出微信门户及利用(18)-微信企业号的通讯录管理支付之成员管理

C#出微信门户及以(17)-微信企业号的通讯录管理支付的部门管理

C#支出微信门户及采取(16)-微信企业号的部署和利用

C#出微信门户及应用(15)-微信菜单增加扫一扫、发图、发地理位置功能

C#支出微信门户及以(14)-在微信菜单中采用重定向得到用户数量

C#出微信门户及采取(13)-使用地理位置扩展相关应用

C#支出微信门户及应用(12)-使用语音处理

C#开发微信门户及运用(11)–微信菜单的又呈现方法介绍

C#开微信门户及动(10)–在管制体系受到同微信用户分组信息

C#付出微信门户及采取(9)-微信门户菜单管理和交至微信服务器

C#出微信门户及利用(8)-微信门户应用管理网功能介绍

C#支出微信门户及用(7)-微信多客服功能和支付并

C#开发微信门户及动(6)–微信门户菜单的田间管理操作

C#开微信门户及采取(5)–用户分组信息保管

C#支出微信门户及应用(4)–关注用户列表及详细信息管理

C#开发微信门户及用(3)–文本信及图文信息之答疑

C#支付微信门户及动(2)–微信信息之处理同回应

C#付出微信门户及使用(1)–开始采用微信接口

在老家过了几乎上吃吃喝喝的光阴,蓝天白云阳光明媚,不能不感慨乡下的好空气。告别乡亲父老之后又再度回雾霾中。

长大后首先赖有人在火车站接送,出站的一瞬目的大脸,有些满足和安心。几上少就好像隔了天长地多,嘻嘻哈哈一道回家。

16年的年终原本计划17年要一个丁在世一样年,作为从不曾远离的等同次于独居时。然而结果计划还是赶不达到扭转,结果于年中启幕了初的处画面。其中有了一样起杀乌龙,事实充分白了结果还再次失落。

17年7月同时去矣故宫和颐和园,前同一不善去还是二十年前之胶卷时代,现在虽到处举在自拍杠了,不过景区里之零食或一样价高。二十年前是让受在去的孩子,这次就改成了伴随在男女一块去的老人家了。故宫和颐和园也或那好,人流那么多,照样没有走个通透,照样要走马观花一般的报到。看看以后还能无克来平等赖真正的走心之一起。

7月底东戴河底亚上同夜间和团游,因为外出匆忙没有未雨绸缪泳衣救生圈,没会下水只是在水边踩在沙子走圈。让海水一点一点地打湿脚面,细腻的沙子一点一点每当现阶段蹋陷,望在对面和海连成一片的御。

搜索了几和房子后,8月之正式迁居到高碑店,陌生的地方陌生的小区。一个同时一个被之包装箱,开始找到各自坐的岗位,空荡的半空中一点点为填满。找超市找小吃然后开头摆灶开火,房子起改为温馨之卷曲点。

9月匆忙促地失去了王府井,拍了些像,吃了中断炸鸡就于回赶,得赶时间去火车站,夜里的车站又是任何一样种则。

10月底之一同上因为那个巴去矣回保定城区,在园林散步,看看因为过往换乘花费了数时间,到莲花池,直隶总督府时便早已接近他们之下班时间,所以都无购置票进入。在邻近转悠了游街,吃了接触小吃就以交车站等车回去。1只多钟头的车程后及小。

17年的另时间里就没有去别的地方了,计划的外出都是18年之动了。

17年尚举行了多梦,各种各样奇奇怪怪的梦。大概是因好旅行,梦里出发去矣广大地方,坐车厢里通过海边和油菜花,满是粉红气球的欧式建筑群,变成小玩偶拉线前执行,绿意满满的十分林,站于茫茫的马路中央……身临其境的美丽梦境,希望18年吗会直接闹梦。