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端调用就好,不然在安卓端会没有效果,而在苹果端会提示签名失败

  • 相关阅读:
    Unix命令大全
    vs2008 与 IE8出现的兼容性问题
    Java 创建文件、文件夹以及临时文件
    如何修改Wamp中mysql默认空密码
    PAT 乙级真题 1003.数素数
    Tags support in htmlText flash as3
    DelphiXE4 FireMonkey 试玩记录,开发IOS应用 还是移植
    10 Great iphone App Review sites to Promote your Apps!
    HTML tags in textfield
    Delphi XE4 IOS 开发, "No eligible applications were found“
  • 原文地址:https://www.cnblogs.com/liuchang/p/6756618.html
Copyright © 2011-2022 走看看