接入微信支付有三种方式:JSAPI,JSSDK,小程序,而小程序的微信支付,官方这次了一次升级优化,对接开发起来相比更加简易,详情可见官方文档(https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa
接入微信支付有三种方式:JSAPI,JSSDK,小程序,而小程序的微信支付,官方这次了一次升级优化,对接开发起来相比更加简易,详情可见官方文档(https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3&index=1)
官方给出的小程序支付交互流程图如下,其实也比较清晰描述了整个过程
宏记(微信号:hongji8410)为了验证这一过程,特地去实操了一下,现整理了下整个过程如下: 首先要准备几个东西
其次,小程序整个支付流程是分为小程序端调用与服务端处理两大块的,其中服务端处理是要与微信服务端进行多次交互处理的。即 小程序->服务端——>微信服务端->服务端->小程序 小程序端发起三次请求,两次向微信服务器(wx.login和wx.requestPayment),中间一次向服务端(wx.request) 服务端发起两次请求与加密处理成签名,两次都是向微信服务器请求,一次请求获取openid,一次统一下单获取prepay_id,加密处理主要是通过MD5然后生成签名参数sign 签名参数sign主要有两个用处,一个是向微信服务端请求预支付时需要用到这个参数,而另一个是返回小程序端调用确认支付里需要用到,而签名的生成都是通过MD5加密appid+openid/prepay_id等参数而成 最后分步讲解下具体过程1. 小程序发起调用wx.login得到jscode,通过wx.request把jscode传送给后台 wx.login({ success:function(res){ if (res.code) { //这里得到jscode即可传到后台进行处理 wx.request({ url:'https://www.voopAPI/getData?js_code='+res.code data: {}, method: 'GET', success: function(res){ //后台处理预支付成功,在这就能得到paySign等确认支付需要的参数 } }) }; }; }); 2. 服务端处理首先根据传过来的jsCode向微信服务器请求session_key和openid public string GetSessionKeyOpenId(string appid, string secret, string js_code) { var url = string.Format("https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code", appid, secret, js_code); var request = WebRequest.Create(url) as HttpWebRequest; var response = request.GetResponse(); var respStream = response.GetResponseStream(); var res = string.Empty; using (var reader = new StreamReader(respStream, Encoding.UTF8)) { res = reader.ReadToEnd(); } return res; } 返回数据
其次根据openid,appid,mch_id等参数封装成一个字符串后用MD5加密后向微信服务器统一下单 var paramter = new WXPayParameters(); paramter.AppId = shopinfo.AppId; paramter.Body = shopinfo.ShopName + "-" + orderpool.OrderPoolCode; paramter.MchId = shopinfo.MchId; paramter.Nonce = WXHandleBll.GetNoncestr(); paramter.Notify_Url = shopinfo.Notify_Url; paramter.Out_Trade_No = orderpool.OrderPoolCode; paramter.Spbill_Create_Ip = "127.0.0.1"; paramter.Total_Fee = "1";//(orderpool.NetAmt).ToString(); 暂时1分,用于测试 paramter.Trade_Type = shopinfo.Trade_type; paramter.Key = shopinfo.Key; var param = WXHandleBll.GetOrderUnifiedParam(reslogion.openid, paramter); MD5加密得出签名sign public string GetOrderUnifiedParam(string openid, WXPayParameters param) { //参与统一下单签名的参数,除最后的key外,已经按参数名ASCII码从小到大排序 var unifiedorderSignParam = string.Format("appid={0}&body={1}&mch_id={2}&nonce_str={3}¬ify_url={4}&openid={5}&out_trade_no={6}&spbill_create_ip={7}&total_fee={8}&trade_type={9}&key={10}" , param.AppId, param.Body, param.MchId, param.Nonce, param.Notify_Url, openid, param.Out_Trade_No, param.Spbill_Create_Ip, param.Total_Fee, param.Trade_Type, param.Key); //MD5 var unifiedorderSign = GetMD5(unifiedorderSignParam).ToUpper(); //构造统一下单的请求参数 var requestParam = string.Format(@"<xml> <appid>{0}</appid> <body>{1}</body> <mch_id>{2}</mch_id> <nonce_str>{3}</nonce_str> <notify_url>{4}</notify_url> <openid>{5}</openid> <out_trade_no>{6}</out_trade_no> <spbill_create_ip>{7}</spbill_create_ip> <total_fee>{8}</total_fee> <trade_type>{9}</trade_type> <sign>{10}</sign> </xml> ", param.AppId, param.Body, param.MchId, param.Nonce, param.Notify_Url, openid, param.Out_Trade_No, param.Spbill_Create_Ip, param.Total_Fee, param.Trade_Type, unifiedorderSign); return requestParam; } 将要MD5的字符串
MD5后的签名
再着,向微信服务再次进行请求(统一下单),获取预支付信息 var RespayXML = WXHandleBll.DoPost(param, "https://api.mch.weixin.qq.com/pay/unifiedorder"); 发送的XML样式
最后,根据统一下单请求返回的参数prepay_id再加上appid等参数封装成一个字符串后用MD5再得出一个签名参数,并且处理其它参数后全部返回小程序端所需要的参数 //3.统一下单后拿到的xml结果 var payRes = XDocument.Parse(RespayXML); var ResXML = payRes.Element("xml"); //序列化相应参数返回给小程序 var res = WXHandleBll.GetPayRequestParam(ResXML, paramter.AppId, paramter.Key); public WXPayRequesEntity GetPayRequestParam(XElement root, string appid, string key) { //当return_code 和result_code都为SUCCESS时才有我们要的prepay_id if (root.Element("return_code").Value == "SUCCESS" && root.Element("result_code").Value == "SUCCESS") { var package = "prepay_id=" + root.Element("prepay_id").Value; var nonceStr = GetNoncestr(); var signType = "MD5"; var timeStamp = Convert.ToInt64((DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds).ToString(); var paySignParam = string.Format("appId={0}&nonceStr={1}&package={2}&signType={3}&timeStamp={4}&key={5}", appid, nonceStr, package, signType, timeStamp, key); var paySign = GetMD5(paySignParam).ToUpper(); var payEntity = new WXPayRequesEntity { package = package, nonceStr = nonceStr, paySign = paySign, signType = signType, timeStamp = timeStamp }; return payEntity; } return new WXPayRequesEntity(); } 返回XML样式
3. 小程序端调用wx.requestPayment弹出密码输入框,再输入密码进行确认支付wx.requestPayment({ timeStamp: res.data.Body.Data.timeStamp, nonceStr: res.data.Body.Data.nonceStr, package: res.data.Body.Data.package, signType: 'MD5', paySign: res.data.Body.Data.paySign, success: function (res) { //确认成功 } });
收集的一些支付坑,方便遇到问题可供查阅
|