zoukankan      html  css  js  c++  java
  • 微信公众号开发小计(三)微信支付

    上周努努力,做完了app端的微信支付,走过了不少的坑坑洼洼,现在写个小总结开发步骤如下:
    1.开通微信的商户平台,在账户中心的api安全中下载安全证书

    2.下载安全证书后,在api秘钥中设置秘钥。

    3.代码开发:

    (1)在配置文件中设置基本信息

     <!--微信开放平台审核通过的应用APPID-->
        <add key="wx_appid" value=""/>
    
        <!--微信支付分配的商户号APPID-->
        <add key="wx_mch_id" value=""/>
    
        <!--wx_key 微信key 密钥-->
        <add key="wx_key" value=""/>
        <!--wxpay_notifyurl 请求回调网址-->
        <add key="wxpay_notifyurl" value=""/>

    (2)创建预支付单

    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    using System.Text;
    using System.Web;
    using System.Web.Http;
    using System.Xml;
    using Travel.Api.AliPayAcc;
    using Travel.Business.Order;
    using Travel.Common;
    using Travel.Common.Bases;
    using Travel.Common.Enum;
    using Travel.Model.Order;
    
    namespace Travel.Api.Controllers
    {
        public class WeChatPayController : ApiController
        {
            // GET: WrChatPay
            [HttpGet]
            public BaseResult GoToPay(Guid? orderId)
            {
                if (orderId.HasValue)
                {
                    var orderinfo = OrderInfoManager.Instance.GetById(orderId);
                    //微信支付 基础配置信息
                    string wx_appid = System.Web.Configuration.WebConfigurationManager.AppSettings["wx_appid"].ToString();
                    //微信开放平台审核通过的应用
                    string wx_mch_id = System.Web.Configuration.WebConfigurationManager.AppSettings["wx_mch_id"].ToString();
                    //微信支付分配的商户号
                    string wx_nonce_str = GetRandomString(20); //随机字符串,不长于32位
    
                    string strcode = "驿马旅行-购买产品";
                    byte[] buffer = Encoding.UTF8.GetBytes(strcode);
                    string wx_body = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
    
                    string wx_out_trade_no = orderinfo.OrderCode + GetRandomString(6);
                    string wx_total_fee = (orderinfo.PayAmount * 100).ToString("f0"); //;//订单总金额,单位为分,详见支付金额
                    string wx_spbill_create_ip = GetWebClientIp(); ////     用户端实际ip
                    string wx_notify_url =
                        System.Web.Configuration.WebConfigurationManager.AppSettings["wxpay_notifyurl"].ToString();
                    string wx_trade_type = "APP";
    
                    var dic = new Dictionary<string, string>
                    {
                        {"appid", wx_appid},
                        {"mch_id", wx_mch_id},
                        {"nonce_str", wx_nonce_str},
                        {"body", wx_body},
                        {"out_trade_no", wx_out_trade_no}, //商户自己的订单号码
                        {"total_fee", wx_total_fee},
                        {"spbill_create_ip", wx_spbill_create_ip}, //服务器的IP地址
                        {"notify_url", wx_notify_url}, //异步通知的地址,不能带参数
                        {"trade_type", wx_trade_type}
                    };
                    //加入签名
                    dic.Add("sign", GetSignString(dic));
                    var sb = new StringBuilder();
                    sb.Append("<xml>");
                    foreach (var d in dic)
                    {
                        sb.Append("<" + d.Key + ">" + d.Value + "</" + d.Key + ">");
                    }
                    sb.Append("</xml>");
                    var xml = new XmlDocument();
                    //  xml.LoadXml(GetPostString("https://api.mch.weixin.qq.com/pay/unifiedorder", sb.ToString()));
                    CookieCollection coo = new CookieCollection();
                    Encoding en = Encoding.GetEncoding("UTF-8");
                    HttpWebResponse response = CreatePostHttpResponse("https://api.mch.weixin.qq.com/pay/unifiedorder",
                        sb.ToString(), en);
                    //打印返回值
                    Stream stream = response.GetResponseStream(); //获取响应的字符串流
                    StreamReader sr = new StreamReader(stream); //创建一个stream读取流
                    string html = sr.ReadToEnd(); //从头读到尾,放到字符串html
                    CreateLog.SaveLogs(html, 1);
                    //Console.WriteLine(html);
                    xml.LoadXml(html);
                    //对请求返回值 进行处理
                    var root = xml.DocumentElement;
                    DataSet ds = new DataSet();
                    StringReader stram = new StringReader(html);
                    XmlTextReader reader = new XmlTextReader(stram);
                    ds.ReadXml(reader);
                    string return_code = ds.Tables[0].Rows[0]["return_code"].ToString();
    
                    //通信成功
                    string result_code = ds.Tables[0].Rows[0]["result_code"].ToString(); //业务结果
                    if (result_code.ToUpper() == "SUCCESS")
                    {
                        string str = GetTimeStamp();
                        var res = new Dictionary<string, string>
                        {
                            {"appid", wx_appid},
                            {"partnerid", wx_mch_id},
                            {"prepayid", root.SelectSingleNode("/xml/prepay_id").InnerText},
                            {"noncestr", dic["nonce_str"]},
                            {"timestamp",str},
                            {"package", "Sign=WXPay"}
                        };
    
                        var paySing = GetSignString(dic);
                        var obj = new
                        {
                            appid = wx_appid,
                            partnerid = wx_mch_id,
                            prepayid = ds.Tables[0].Rows[0]["prepay_id"].ToString(),
                            noncestr = wx_nonce_str,
                            timestamp = str,
                            sign = GetSignString(res),
                        };
                        return new BaseResult(true, obj);
                    }
                    else
                    {
                        return new BaseResult(false, null, "请求失败");
                    }
                }
                else
                {
                    return new BaseResult(false, null, "参数错误");
                }
            }
    
            [HttpGet]
            public string WeChatPayCallBack()
            {
                try
                {
                    CreateLog.SaveLogs("==========================================", 1);
                    HttpContextBase context = (HttpContextBase)Request.Properties["MS_HttpContext"];
                    HttpRequestBase request = context.Request;
                    string status = request["result_code"];
                    if (status == "SUCCESS")
                    {
                        var oderInfo = OrderInfoManager.Instance.GetByField("OrderCode", request["out_trade_no"].Substring(0, request["out_trade_no"].ToString().Length - 6)).FirstOrDefault();
                        if (oderInfo != null)
                        {
                            PaymentInfo info = new PaymentInfo()
                            {
                                OrderGuid = oderInfo.Guid,
                                PayState = 1,
                                PayMethod = (int)PayMethod.支付宝支付,
                                Guid = Guid.NewGuid(),
                                Mark = (int)DataMark.正常,
                                PayDateTime = DateTime.Now,
                                PayMoney = Convert.ToDecimal(request["total_fee"]) / 100,
                                Qid = request["transaction_id"]
                            };
                            PaymentInfoManager.Instance.Insert(info);
                        }
                    }
                }
                catch (Exception e)
                {
    
                    e.WriteLog(e.Message);
                }
                return "111111111";
            }
            #region 微信辅助方法
            /// <summary>
            /// 从字符串里随机得到,规定个数的字符串.
            /// </summary>
            /// <param name="allChar"></param>
            /// <param name="CodeCount"></param>
            /// <returns></returns>
            public static string GetRandomString(int CodeCount)
            {
                string allChar = "1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,i,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z";
                string[] allCharArray = allChar.Split(',');
                string RandomCode = "";
                int temp = -1;
                Random rand = new Random();
                for (int i = 0; i < CodeCount; i++)
                {
                    if (temp != -1)
                    {
                        rand = new Random(temp * i * ((int)DateTime.Now.Ticks));
                    }
                    int t = rand.Next(allCharArray.Length - 1);
                    while (temp == t)
                    {
                        t = rand.Next(allCharArray.Length - 1);
                    }
                    temp = t;
                    RandomCode += allCharArray[t];
                }
    
                return RandomCode;
            }
    
            public static string GetWebClientIp()
            {
                string userIP = "IP";
    
                try
                {
                    if (System.Web.HttpContext.Current == null
                || System.Web.HttpContext.Current.Request == null
                || System.Web.HttpContext.Current.Request.ServerVariables == null)
                        return "";
    
                    string CustomerIP = "";
    
                    //CDN加速后取到的IP   
                    CustomerIP = System.Web.HttpContext.Current.Request.Headers["Cdn-Src-Ip"];
                    if (!string.IsNullOrEmpty(CustomerIP))
                    {
                        return CustomerIP;
                    }
    
                    CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
    
    
                    if (!String.IsNullOrEmpty(CustomerIP))
                        return CustomerIP;
    
                    if (System.Web.HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null)
                    {
                        CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
                        if (CustomerIP == null)
                            CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
                    }
                    else
                    {
                        CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
    
                    }
    
                    if (string.Compare(CustomerIP, "unknown", true) == 0)
                        return System.Web.HttpContext.Current.Request.UserHostAddress;
                    return CustomerIP;
                }
                catch { }
    
                return userIP;
            }
    
            private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
            {
                return true; //总是接受   
            }
    
            public static HttpWebResponse CreatePostHttpResponse(string url, string datas, Encoding charset)
            {
                HttpWebRequest request = null;
                //HTTPSQ请求
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                request = WebRequest.Create(url) as HttpWebRequest;
                request.ProtocolVersion = HttpVersion.Version10;
                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";
    
                //如果需要POST数据   
                //if (!(parameters == null || parameters.Count == 0))
                //{
                StringBuilder buffer = new StringBuilder();
                //int i = 0;
                //foreach (string key in parameters.Keys)
                //{
                //    if (i > 0)
                //    {
                //        buffer.AppendFormat("&{0}={1}", key, parameters[key]);
                //    }
                //    else
                //    {
                //        buffer.AppendFormat("{0}={1}", key, parameters[key]);
                //    }
                //    i++;
                //}
                buffer.AppendFormat(datas);
                byte[] data = charset.GetBytes(buffer.ToString());
                using (Stream stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }
                //}
                return request.GetResponse() as HttpWebResponse;
            }
    
            public string GetSignString(Dictionary<string, string> dic)
            {
                string key = System.Web.Configuration.WebConfigurationManager.AppSettings["wx_key"].ToString(); ;//商户平台 API安全里面设置的KEY  32位长度
                //排序
                dic = dic.OrderBy(d => d.Key).ToDictionary(d => d.Key, d => d.Value);
                //连接字段
                var sign = dic.Aggregate("", (current, d) => current + (d.Key + "=" + d.Value + "&"));
                sign += "key=" + key;
                //MD5
                sign = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sign, "MD5").ToUpper();
    
                return sign;
            }
    
            /// <summary>  
            /// 获取时间戳  
            /// </summary>  
            /// <returns></returns>  
            public static string GetTimeStamp()
            {
                TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
                return Convert.ToInt64(ts.TotalSeconds).ToString();
            }
            #endregion
        }
    }

    (3)设置回调方法

    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Web;
    using System.Web.Mvc;
    using System.Xml;
    using Travel.Business.Order;
    using Travel.Common.Enum;
    using Travel.Model.Order;
    using Travel.WeChat.WeCahtCode;
    
    namespace Travel.WeChat.Controllers
    {
        public class WeChatPayController : Controller
        {
            // GET: WeChatPay
            public ActionResult Index()
            {
                 CreateLog.SaveLogs("========开始============", 1);
                String xmlData = getPostStr();//获取请求数据
                //CreateLog.SaveLogs(xmlData, 1);
                if (xmlData == "")
                {
    
                }
                else
                {
                    // CreateLog.SaveLogs("22222222222222222222", 1);
                    var dic = new Dictionary<string, string>
                    {
                        {"return_code", "SUCCESS"},
                        {"return_msg","OK"}
       
                    };
                    var sb = new StringBuilder();
                    sb.Append("<xml>");
    
    
                    foreach (var d in dic)
                    {
                        sb.Append("<" + d.Key + ">" + d.Value + "</" + d.Key + ">");
                    }
                    sb.Append("</xml>");
    
    
    
    
    
                    //把数据重新返回给客户端
                    DataSet ds = new DataSet();
                    StringReader stram = new StringReader(xmlData);
                    XmlTextReader datareader = new XmlTextReader(stram);
                    ds.ReadXml(datareader);
                    if (ds.Tables[0].Rows[0]["return_code"].ToString() == "SUCCESS")
                    {
    
    
                        string wx_appid = "";//微信开放平台审核通过的应用APPID
                        string wx_mch_id = "";//微信支付分配的商户号
    
                        string wx_nonce_str = "";//     随机字符串,不长于32位
                        string wx_sign = "";//签名,详见签名算法
                        string wx_result_code = "";//SUCCESS/FAIL
    
                        string wx_return_code = "";
                        string wx_openid = "";//用户在商户appid下的唯一标识
                        string wx_is_subscribe = "";//用户是否关注公众账号,Y-关注,N-未关注,仅在公众账号类型支付有效
                        string wx_trade_type = "";//     APP
                        string wx_bank_type = "";//     银行类型,采用字符串类型的银行标识,银行类型见银行列表
                        string wx_fee_type = "";//     货币类型,符合ISO4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
    
    
                        string wx_transaction_id = "";//微信支付订单号
                        string wx_out_trade_no = "";//商户系统的订单号,与请求一致。
                        string wx_time_end = "";//     支付完成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
                        int wx_total_fee = -1;//     订单总金额,单位为分
                        int wx_cash_fee = -1;//现金支付金额订单现金支付金额,详见支付金额
    
    
                        #region  数据解析
                        //列 是否存在
                        string signstr = "";//需要前面的字符串
                        //wx_appid
                        if (ds.Tables[0].Columns.Contains("appid"))
                        {
                            wx_appid = ds.Tables[0].Rows[0]["appid"].ToString();
                            if (!string.IsNullOrEmpty(wx_appid))
                            {
                                signstr += "appid=" + wx_appid;
                            }
                        }
    
                        //wx_bank_type
                        if (ds.Tables[0].Columns.Contains("bank_type"))
                        {
                            wx_bank_type = ds.Tables[0].Rows[0]["bank_type"].ToString();
                            if (!string.IsNullOrEmpty(wx_bank_type))
                            {
                                signstr += "&bank_type=" + wx_bank_type;
                            }
                        }
                        //wx_cash_fee
                        if (ds.Tables[0].Columns.Contains("cash_fee"))
                        {
                            wx_cash_fee = Convert.ToInt32(ds.Tables[0].Rows[0]["cash_fee"].ToString());
    
                            signstr += "&cash_fee=" + wx_cash_fee;
                        }
                        //wx_fee_type
                        if (ds.Tables[0].Columns.Contains("fee_type"))
                        {
                            wx_fee_type = ds.Tables[0].Rows[0]["fee_type"].ToString();
                            if (!string.IsNullOrEmpty(wx_fee_type))
                            {
                                signstr += "&fee_type=" + wx_fee_type;
                            }
                        }
    
                        //wx_is_subscribe
                        if (ds.Tables[0].Columns.Contains("is_subscribe"))
                        {
                            wx_is_subscribe = ds.Tables[0].Rows[0]["is_subscribe"].ToString();
                            if (!string.IsNullOrEmpty(wx_is_subscribe))
                            {
                                signstr += "&is_subscribe=" + wx_is_subscribe;
                            }
                        }
    
                        //wx_mch_id
                        if (ds.Tables[0].Columns.Contains("mch_id"))
                        {
                            wx_mch_id = ds.Tables[0].Rows[0]["mch_id"].ToString();
                            if (!string.IsNullOrEmpty(wx_mch_id))
                            {
                                signstr += "&mch_id=" + wx_mch_id;
                            }
                        }
    
                        //wx_nonce_str
                        if (ds.Tables[0].Columns.Contains("nonce_str"))
                        {
                            wx_nonce_str = ds.Tables[0].Rows[0]["nonce_str"].ToString();
                            if (!string.IsNullOrEmpty(wx_nonce_str))
                            {
                                signstr += "&nonce_str=" + wx_nonce_str;
                            }
                        }
    
                        //wx_openid
                        if (ds.Tables[0].Columns.Contains("openid"))
                        {
                            wx_openid = ds.Tables[0].Rows[0]["openid"].ToString();
                            if (!string.IsNullOrEmpty(wx_openid))
                            {
                                signstr += "&openid=" + wx_openid;
                            }
                        }
    
                        //wx_out_trade_no
                        if (ds.Tables[0].Columns.Contains("out_trade_no"))
                        {
                            wx_out_trade_no = ds.Tables[0].Rows[0]["out_trade_no"].ToString();
                            if (!string.IsNullOrEmpty(wx_out_trade_no))
                            {
                                signstr += "&out_trade_no=" + wx_out_trade_no;
                            }
                        }
    
                        //wx_result_code 
                        if (ds.Tables[0].Columns.Contains("result_code"))
                        {
                            wx_result_code = ds.Tables[0].Rows[0]["result_code"].ToString();
                            if (!string.IsNullOrEmpty(wx_result_code))
                            {
                                signstr += "&result_code=" + wx_result_code;
                            }
                        }
    
                        //wx_result_code 
                        if (ds.Tables[0].Columns.Contains("return_code"))
                        {
                            wx_return_code = ds.Tables[0].Rows[0]["return_code"].ToString();
                            if (!string.IsNullOrEmpty(wx_return_code))
                            {
                                signstr += "&return_code=" + wx_return_code;
                            }
                        }
    
                        //wx_sign 
                        if (ds.Tables[0].Columns.Contains("sign"))
                        {
                            wx_sign = ds.Tables[0].Rows[0]["sign"].ToString();
                        }
    
                        //wx_time_end
                        if (ds.Tables[0].Columns.Contains("time_end"))
                        {
                            wx_time_end = ds.Tables[0].Rows[0]["time_end"].ToString();
                            if (!string.IsNullOrEmpty(wx_time_end))
                            {
                                signstr += "&time_end=" + wx_time_end;
                            }
                        }
    
                        //wx_total_fee
                        if (ds.Tables[0].Columns.Contains("total_fee"))
                        {
                            wx_total_fee = Convert.ToInt32(ds.Tables[0].Rows[0]["total_fee"].ToString());
    
                            signstr += "&total_fee=" + wx_total_fee;
                        }
    
                        //wx_trade_type
                        if (ds.Tables[0].Columns.Contains("trade_type"))
                        {
                            wx_trade_type = ds.Tables[0].Rows[0]["trade_type"].ToString();
                            if (!string.IsNullOrEmpty(wx_trade_type))
                            {
                                signstr += "&trade_type=" + wx_trade_type;
                            }
                        }
    
                        //wx_transaction_id
                        if (ds.Tables[0].Columns.Contains("transaction_id"))
                        {
                            wx_transaction_id = ds.Tables[0].Rows[0]["transaction_id"].ToString();
                            if (!string.IsNullOrEmpty(wx_transaction_id))
                            {
                                signstr += "&transaction_id=" + wx_transaction_id;
                            }
                        }
    
                        #endregion
                        //追加key 密钥
                        signstr += "&key=" + System.Web.Configuration.WebConfigurationManager.AppSettings["wx_key"].ToString();
                        CreateLog.SaveLogs("签名字符串" + signstr, 1);
                        //签名正确
                        string orderStrwhere = "ordernumber='" + wx_out_trade_no + "'"; 
                        if (wx_sign == System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(signstr, "MD5").ToUpper())
                        {
                            CreateLog.SaveLogs("开始付款",1);
                            //签名正确   处理订单操作逻辑
                            var oderInfo = OrderInfoManager.Instance.GetByField("OrderCode", wx_out_trade_no.Substring(0, wx_out_trade_no.ToString().Length - 6)).FirstOrDefault();
                            if (oderInfo.OrderState != (int) OrderState.代付款)
                            {
                                CreateLog.SaveLogs("支付成功!但是在此发出请求" , 1);
                                return null;
                            }
                            if (oderInfo != null)
                            {
                                PaymentInfo info = new PaymentInfo()
                                {
                                    OrderGuid = oderInfo.Guid,
                                    PayState = 1,
                                    PayMethod = (int)PayMethod.微信支付,
                                    Guid = Guid.NewGuid(),
                                    Mark = (int)DataMark.正常,
                                    PayDateTime = DateTime.Now,
                                    PayMoney = Convert.ToDecimal(wx_total_fee) / 100,
                                    Qid = wx_transaction_id
                                };
                                PaymentInfoManager.Instance.Insert(info);
                            }
                            CreateLog.SaveLogs("状态修改结束", 1);
                        }
                        else
                        {
                            
                        }
                        {
                            //追加备注信息
                            CreateLog.SaveLogs("签名失败", 1);
                        }
    
                    }
                    else
                    {
                        // 返回信息,如非空,为错误原因  签名失败 参数格式校验错误
                        string return_msg = ds.Tables[0].Rows[0]["return_msg"].ToString();
                        CreateLog.SaveLogs("支付失败", 1);
    
                    }
    
                }
                return View();
            }
    
    
            //获得Post过来的数据
            public string getPostStr()
            {
                Int32 intLen = Convert.ToInt32(Request.InputStream.Length);
                byte[] b = new byte[intLen];
                Request.InputStream.Read(b, 0, intLen);
                return System.Text.Encoding.UTF8.GetString(b);
            }
        }
    }

    注意:在生成预支付订单的时候要进行两次签名,第一次请求预支付订单号的签名一次,生成之后再进行一次签名,将数据返回给app端 然后app端调用就好,不然在安卓端会没有效果,而在苹果端会提示签名失败

  • 相关阅读:
    设计模式
    IPC- Posix与system v
    squashfs文件系统
    各种根文件系统
    SPI通讯协议
    tty各种设备的情况
    Linux系统调用过程
    uImage和zImage的区别
    jquery可见性选择器(匹配匹配所有显示的元素)
    jquery可见性选择器(匹配所有隐藏的元素)
  • 原文地址:https://www.cnblogs.com/liuchang/p/6756618.html
Copyright © 2011-2022 走看看