微信小程序之微信支付C#后台(统一下单)
一、微信小程序支付
1、微信小程序端请求支付接口
商户在小程序中先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易后调起支付。具体可以查看接口示例。
接口传入参数示例:
<xml> <appid>wx2421b1c4370ec43b</appid> <attach>支付测试</attach> <body>JSAPI支付测试</body> <mch_id>10000100</mch_id> <nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str> <notify_url>http://wxpay.wxutil.com/pub_v2/pay/notify.v2.php</notify_url> <openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid> <out_trade_no>1415659990</out_trade_no> <spbill_create_ip>14.23.150.211</spbill_create_ip> <total_fee>1</total_fee> <trade_type>JSAPI</trade_type> <sign>0CB01533B8C1EF103065174F50BCA001</sign> </xml>
接口返回示例:
<xml> <return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> <appid><![CDATA[wx2421b1c4370ec43b]]></appid> <mch_id><![CDATA[10000100]]></mch_id> <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str> <openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid> <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign> <result_code><![CDATA[SUCCESS]]></result_code> <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id> <trade_type><![CDATA[JSAPI]]></trade_type> </xml>
二、接口调用(C#)
1、支付接口方法
//获取请求数据 Dictionary<string, string> strParam = new Dictionary<string, string>(); //小程序ID strParam.Add("appid", PayInfo.appid); //附加数据 strParam.Add("attach", PayInfo.attach); //商品描述 strParam.Add("body", PayInfo.body); //商户号 strParam.Add("mch_id", PayInfo.mchid); //随机字符串 strParam.Add("nonce_str", PayInfo.nonceStr); //通知地址 (异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。) strParam.Add("notify_url", PayInfo.notifyUrl); //用户标识 strParam.Add("openid", openId); //商户订单号 strParam.Add("out_trade_no", orderNum); //终端IP strParam.Add("spbill_create_ip", PayInfo.addrIp); //标价金额 strParam.Add("total_fee", Convert.ToInt32(orderTotal * 100).ToString()); //交易类型 strParam.Add("trade_type", PayInfo.tradeType); strParam.Add("sign", PayHelper.GetSignInfo(strParam, PayInfo.key)); //获取预支付ID string preInfo = Utility.PostHttpResponse(PayInfo.orderUrl, PayHelper.CreateXmlParam(strParam)); string strCode = PayHelper.GetXmlValue(preInfo, "return_code"); string strMsg = PayHelper.GetXmlValue(preInfo, "return_msg"); if (strCode == "SUCCESS") { //再次签名 string nonecStr = PayInfo.nonceStr; string timeStamp = PayInfo.timeStamp; string package = "prepay_id=" + PayHelper.GetXmlValue(preInfo, "prepay_id"); Dictionary<string, string> singInfo = new Dictionary<string, string>(); singInfo.Add("appId", PayInfo.appid); singInfo.Add("nonceStr", nonecStr); singInfo.Add("package", package); singInfo.Add("signType", PayInfo.signType); singInfo.Add("timeStamp", timeStamp); //返回参数 info.Msg = strMsg; info.Code = strCode; info.Id = orderId; info.appId = PayInfo.appid; info.orderGuId = orderNum; info.Package = package; info.TimeStamp = timeStamp; info.NonceStr = nonecStr; info.SignType = PayInfo.signType; info.PaySign = PayHelper.GetSignInfo(singInfo, PayInfo.key); listMsg.Add(info); result = u.SuccessMsg(listMsg, "", ""); } else { info.Code = strCode; info.Msg = strMsg; listMsg.Add(info); result = u.FailMsg(listMsg); }
2、支付结果通知API
/// <summary> /// 支付结果通知API /// </summary> /// <returns></returns> [HttpPost] public string OrderNotify() { string strResult = string.Empty; try { //1.获取微信通知的参数 string strXML = Utility.GetPostStr(); //判断是否请求成功 if (PayHelper.GetXmlValue(strXML, "return_code") == "SUCCESS") { //判断是否支付成功 if (PayHelper.GetXmlValue(strXML, "result_code") == "SUCCESS") { //获得签名 string getSign = PayHelper.GetXmlValue(strXML, "sign"); //进行签名 string sign = PayHelper.GetSignInfo(PayHelper.GetFromXml(strXML), PayInfo.key); if (sign == getSign) { //校验订单信息 string wxOrderNum = PayHelper.GetXmlValue(strXML, "transaction_id"); //微信订单号 string orderNum = PayHelper.GetXmlValue(strXML, "out_trade_no"); //商户订单号 string orderTotal = PayHelper.GetXmlValue(strXML, "total_fee"); string openid = PayHelper.GetXmlValue(strXML, "openid"); //校验订单是否存在 if (true) { //2.更新订单的相关状态 //3.返回一个xml格式的结果给微信服务器 if (obj > 0) { strResult = PayHelper.GetReturnXml("SUCCESS", "OK"); } else { strResult = PayHelper.GetReturnXml("FAIL", "订单状态更新失败"); } } else { strResult = PayHelper.GetReturnXml("FAIL", "支付结果中微信订单号数据库不存在!"); } } else { strResult = PayHelper.GetReturnXml("FAIL", "签名不一致!"); } } else { strResult = PayHelper.GetReturnXml("FAIL", "支付通知失败!"); } } else { strResult = PayHelper.GetReturnXml("FAIL", "支付通知失败!"); } #endregion } catch (Exception ex) { } return strResult; }
3、Utility类
/// <summary> /// 获得Post过来的数据 /// </summary> /// <returns></returns> public static string GetPostStr() { Int32 intLen = Convert.ToInt32(HttpContext.Current.Request.InputStream.Length); byte[] b = new byte[intLen]; HttpContext.Current.Request.InputStream.Read(b, 0, intLen); return Encoding.UTF8.GetString(b); } /// <summary> /// 模拟POST提交 /// </summary> /// <param name="url">请求地址</param> /// <param name="xmlParam">xml参数</param> /// <returns>返回结果</returns> public static string PostHttpResponse(string url, string xmlParam) { HttpWebRequest myHttpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); myHttpWebRequest.Method = "POST"; myHttpWebRequest.ContentType = "application/x-www-form-urlencoded;charset=utf-8"; // Encode the data byte[] encodedBytes = Encoding.UTF8.GetBytes(xmlParam); myHttpWebRequest.ContentLength = encodedBytes.Length; // Write encoded data into request stream Stream requestStream = myHttpWebRequest.GetRequestStream(); requestStream.Write(encodedBytes, 0, encodedBytes.Length); requestStream.Close(); HttpWebResponse result; try { result = (HttpWebResponse)myHttpWebRequest.GetResponse(); } catch { return string.Empty; } if (result.StatusCode == HttpStatusCode.OK) { using (Stream mystream = result.GetResponseStream()) { using (StreamReader reader = new StreamReader(mystream)) { return reader.ReadToEnd(); } } } return null; }
4、PayHelper类
#region 生成签名 /// <summary> /// 获取签名数据 ///</summary> /// <param name="strParam"></param> /// <param name="key"></param> /// <returns></returns> public static string GetSignInfo(Dictionary<string, string> strParam, string key) { int i = 0; string sign = string.Empty; StringBuilder sb = new StringBuilder(); try { foreach (KeyValuePair<string, string> temp in strParam) { if (temp.Value == "" || temp.Value == null || temp.Key.ToLower() == "sign") { continue; } i++; sb.Append(temp.Key.Trim() + "=" + temp.Value.Trim() + "&"); } sb.Append("key=" + key.Trim() + ""); sign = MD5Core.GetHashString(sb.ToString(), Encoding.UTF8).ToUpper(); } catch (Exception ex) { Utility.AddLog("PayHelper", "GetSignInfo", ex.Message, ex); } return sign; } #endregion #region XML 处理 /// <summary> /// 获取XML值 /// </summary> /// <param name="strXml">XML字符串</param> /// <param name="strData">字段值</param> /// <returns></returns> public static string GetXmlValue(string strXml, string strData) { string xmlValue = string.Empty; XmlDocument xmlDocument = new XmlDocument(); xmlDocument.LoadXml(strXml); var selectSingleNode = xmlDocument.DocumentElement.SelectSingleNode(strData); if (selectSingleNode != null) { xmlValue = selectSingleNode.InnerText; } return xmlValue; } /// <summary> /// 集合转换XML数据 (拼接成XML请求数据) /// </summary> /// <param name="strParam">参数</param> /// <returns></returns> public static string CreateXmlParam(Dictionary<string, string> strParam) { StringBuilder sb = new StringBuilder(); try { sb.Append("<xml>"); foreach (KeyValuePair<string, string> k in strParam) { if (k.Key == "attach" || k.Key == "body" || k.Key == "sign") { sb.Append("<" + k.Key + "><![CDATA[" + k.Value + "]]></" + k.Key + ">"); } else { sb.Append("<" + k.Key + ">" + k.Value + "</" + k.Key + ">"); } } sb.Append("</xml>"); } catch (Exception ex) { Utility.AddLog("PayHelper", "CreateXmlParam", ex.Message, ex); } return sb.ToString(); } /// <summary> /// XML数据转换集合(XML数据拼接成字符串) /// </summary> /// <param name="xmlString"></param> /// <returns></returns> public static Dictionary<string, string> GetFromXml(string xmlString) { Dictionary<string, string> sParams = new Dictionary<string, string>(); try { XmlDocument doc = new XmlDocument(); doc.LoadXml(xmlString); XmlElement root = doc.DocumentElement; int len = root.ChildNodes.Count; for (int i = 0; i < len; i++) { string name = root.ChildNodes[i].Name; if (!sParams.ContainsKey(name)) { sParams.Add(name.Trim(), root.ChildNodes[i].InnerText.Trim()); } } } catch (Exception ex) { Utility.AddLog("PayHelper", "GetFromXml", ex.Message, ex); } return sParams; } /// <summary> /// 返回通知 XML /// </summary> /// <param name="returnCode"></param> /// <param name="returnMsg"></param> /// <returns></returns> public static string GetReturnXml(string returnCode, string returnMsg) { StringBuilder sb = new StringBuilder(); sb.Append("<xml>"); sb.Append("<return_code><![CDATA[" + returnCode + "]]></return_code>"); sb.Append("<return_msg><![CDATA[" + returnMsg + "]]></return_msg>"); sb.Append("</xml>"); return sb.ToString(); } #endregion
5、PayInfo类
public class PayInfo { /// <summary> /// 小程序登录API /// </summary> public static string loginUrl = ConfigurationManager.AppSettings["loginurl"].ToString(); /// <summary> /// 统一下单API /// </summary> public static string orderUrl = ConfigurationManager.AppSettings["orderurl"].ToString(); /// <summary> /// 支付结果通知API /// </summary> public static string notifyUrl = ConfigurationManager.AppSettings["notifyurl"].ToString(); /// <summary> /// 查询订单API /// </summary> public static string queryUrl = ConfigurationManager.AppSettings["queryurl"].ToString(); /// <summary> /// 申请退款API /// </summary> public static string refundUrl = ConfigurationManager.AppSettings["refundurl"].ToString(); /// <summary> /// 退款通知API /// </summary> public static string refundNotifyUrl = ConfigurationManager.AppSettings["refundnotifyurl"].ToString(); /// <summary> /// 退款通知API /// </summary> public static string refundQueryUrl = ConfigurationManager.AppSettings["refundqueryurl"].ToString(); /// <summary> /// 小程序唯一标识 /// </summary> public static string appid = ConfigurationManager.AppSettings["appid"].ToString(); /// <summary> /// 小程序的 app secret /// </summary> public static string secret = ConfigurationManager.AppSettings["secret"].ToString(); /// <summary> /// 小程序的授权类型 /// </summary> public static string grantType = ConfigurationManager.AppSettings["grant_type"].ToString(); /// <summary> /// 商户号(微信支付分配的商户号) /// </summary> public static string mchid = ConfigurationManager.AppSettings["mch_id"].ToString(); /// <summary> ///商户平台设置的密钥key /// </summary> public static string key = ConfigurationManager.AppSettings["key"].ToString(); /// <summary> /// 随机字符串不长于 32 位 /// </summary> public static string nonceStr = PayHelper.GetNonceStr(); /// <summary> /// 时间戳 从1970年1月1日00:00:00至今的秒数,即当前的时间 /// </summary> public static string timeStamp = PayHelper.GetTimeStamp(); /// <summary> /// 终端IP APP和网页支付提交用户端IP, /// </summary> public static string addrIp = PayHelper.GetIP; /// <summary> /// 交易类型 小程序取值如下:JSAPI /// </summary> public static string tradeType = "JSAPI"; /// <summary> /// 签名类型 默认为MD5,支持HMAC-SHA256和MD5。 /// </summary> public static string signType = "MD5"; /// <summary> /// 商品描述 商品简单描述,该字段请按照规范传递 /// </summary> public static string body = "奇小爱的异想世界-支付"; /// <summary> /// 附加数据 在查询API和支付通知中原样返回 /// </summary> public static string attach = "微信支付信息"; /// <summary> /// 签名,参与签名参数:appid,mch_id,transaction_id,out_trade_no,nonce_str,key /// </summary> public string sign = ""; /// <summary> /// 微信订单号,优先使用 /// </summary> public static string transactionid = ""; /// <summary> /// 商户系统内部订单号 /// </summary> public static string out_trade_no = ""; /// <summary> /// 商户退款单号 /// </summary> public static string out_refund_no = ""; /// <summary> /// 退款金额 /// </summary> public static decimal refundfee; /// <summary> /// 订单金额 /// </summary> public static decimal totalfee; }
三、微信小程序调用
1、小程序调用方法,发起支付,具体如下:
微信小程序支付方发起微信支付。
2、示例代码:
wx.requestPayment({ 'timeStamp': '', 'nonceStr': '', 'package': '', 'signType': 'MD5', 'paySign': '', 'success':function(res){ }, 'fail':function(res){ } })
3、测试完成支付
优秀是一种习惯,欢迎大家关注学习