zoukankan      html  css  js  c++  java
  • 微信小程序支付服务端.net core实现,简单直接

    做小程序的支付时,在翻阅了大量的别人分享的代码后,感觉写的简直就是一堆垃圾,不敢苟同,要是代码都那么写,维护性简直了,于是才有了这篇文章。

    首先流程是很清楚的,就是先统一下单拼一个xml,然后把有值的参数排序后做计算一个签名,把签名也写到xml中,提交给微信,返回发起支付需要的参数,紧接着进行二次签名,将结果返回给小程序,小程序去调微信api发起支付

    1,将需要拼接程xml的参数都写到一个类里边

     [Serializable]
        [XmlRoot(ElementName = "xml", Namespace = "",IsNullable =true,DataType ="")]
        public class WxUnifiedOrder
        {
            [XmlElement(ElementName = "appid")]
            public string AppId { get; set; }
            [XmlElement(ElementName = "mch_id")]
            public string Mch_Id { get; set; }
            [XmlElement(ElementName = "device_info")]
            public string Device_Info { get; set; }
            [XmlElement(ElementName = "nonce_str")]
            public string Nonce_Str { get; set; }
    
            [XmlElement(ElementName = "sign")]
            public string Sign { get; set; }
            /// <summary>
            /// 商品描述
            /// </summary>
            [XmlElement(ElementName = "body")]
            public string Body { get; set; }
            /// <summary>
            /// 商户订单号
            /// </summary>
            [XmlElement(ElementName = "out_trade_no")]
            public string Out_Trade_No { get; set; }
            /// <summary>
            /// 订单金额
            /// </summary>
            [XmlElement(ElementName = "total_fee")]
            public int Total_Fee { get; set; }
            /// <summary>
            /// 终端IP
            /// </summary>
            [XmlElement(ElementName = "spbill_create_ip")]
            public string Spbill_Create_Ip { get; set; }
            /// <summary>
            /// 通知地址
            /// </summary>
            [XmlElement(ElementName = "notify_url")]
            public string Notify_Url { get; set; }
            /// <summary>
            /// 交易类型
            /// </summary>
            [XmlElement(ElementName = "trade_type")]
            public string Trade_Type { get; set; }
    
            [XmlElement(ElementName = "openid")]
            public string OpenId { get; set; }

    加上特性,标明最终生成xml的文档结构。

    2,写个xml简单的操作类,就是个序列化和反序列化的过程

     public static class XMLOption
        {
            public static string ToXml<T>(this T obj, Encoding encoding)
            {
                string result = string.Empty;
                try
                {
                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());
                        //序列化对象
                        XmlSerializerNamespaces namespaes = new XmlSerializerNamespaces();
                        namespaes.Add("", "");
                        XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, encoding);
                        xmlTextWriter.Formatting = System.Xml.Formatting.None;
                        xmlSerializer.Serialize(xmlTextWriter, obj, namespaes);
                        xmlTextWriter.Flush();
                        xmlTextWriter.Close();
                        result = encoding.GetString(memoryStream.ToArray());
                    }
                }
                catch (Exception ex)
                {
    
                }
                return result;
            }
    
            public static T ToXmlObject<T>(this string str, Encoding encoding)
            {
                try
                {
                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                       
                        var buffer = encoding.GetBytes(str);
                        memoryStream.Write(buffer, 0, buffer.Length);
                        memoryStream.Position = 0;
                        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
                        var result = xmlSerializer.Deserialize(memoryStream);
                        return (T)result;
                    }
                }
                catch (Exception ex)
                {
                    return default;
                }
            }
        }
    View Code

    3.一个模拟post请求的公用方法

     /// <summary>  
            /// 模拟POST提交  
            /// </summary>  
            /// <param name="url">请求地址</param>  
            /// <param name="xmlParam">xml参数</param>  
            /// <returns>返回结果</returns>  
            public 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;
            }
    View Code

    4.再来一个扩展方法,计算string字符串的md5值

     /// <summary>
            /// 对字符串进行MD5加密
            /// </summary>
            /// <param name="strIN">需要加密的字符串</param>
            /// <returns>密文</returns>
            public static string MD5(this string source)
            {
                if (source == null)
                {
                    return null;
                }
                using (MD5 md5 = System.Security.Cryptography.MD5.Create())
                {
                    byte[] result = md5.ComputeHash(Encoding.UTF8.GetBytes(source));
                    string strResult = BitConverter.ToString(result);
                    return strResult.Replace("-", "");
                }
            }
    View Code

    5.填充需要提交的信息,并计算签名

     var wxUnifiedOrder = new WxUnifiedOrder()
                {
                    AppId = wxsetting.Appid,
                    Body = product.Name,
                    Device_Info = "WEB",
                    Mch_Id = wxsetting.Mch_id,
                    Nonce_Str = Guid.NewGuid().ToString().Replace("-", "").ToUpper(),
                    Notify_Url = _configuration["WechatPaied:Notify_Url"],
                    Out_Trade_No = orderinfo.OrderCode,
                    Sign = null,
                    Spbill_Create_Ip = _configuration["WechatPaied:Spbill_Create_Ip"],
                    Total_Fee = 1,// Convert.ToInt32(orderinfo.TotalPrice * 100)
                    Trade_Type = "JSAPI",
                    OpenId = uinfo.OpenId
                };
                var type = wxUnifiedOrder.GetType();
                SortedDictionary<string, string> param = new SortedDictionary<string, string>();
                foreach (var item in type.GetProperties())
                {
                    if (item.GetValue(wxUnifiedOrder) != null && item.Name != "Sign")
                    {
                        param.Add(item.Name.ToLower(), item.GetValue(wxUnifiedOrder).ToString());
                    }
                }
                List<string> lstparams = new List<string>();
                foreach (var item in param)
                {
                    lstparams.Add(string.Concat(item.Key, "=", item.Value));
                }
                lstparams.Add(string.Concat("key", "=", _configuration["WechatPaied:Api_Key"]));
                string param_Sign = string.Join("&", lstparams);
                wxUnifiedOrder.Sign =param_Sign.MD5().ToUpper();//计算签名

    这里的 SortedDictionary提供的就是一个排序后的参数列表,紧接着把他们按照排列好的顺序,拼起来,最后把key加上,调用.MD5这个扩展方法计算签名,把model填充起来

    6.模拟请求一下微信提供的接口,执行统一下单,拿到返回值

    string xmldoc = wxUnifiedOrder.ToXml(Encoding.UTF8);
    var result = PostHttpResponse("https://api.mch.weixin.qq.com/pay/unifiedorder", xmldoc);
    var resultData = result.ToXmlObject<WxUnifiedOrderResponse>(Encoding.UTF8);
    PostHttpResponse 方法上文已提供 .ToXml .ToXmlObject上文也有提供,就是操作xml序列化的那两
    6.1:WxUnifiedOrderResponse model内容:
     [System.SerializableAttribute()]
        [System.ComponentModel.DesignerCategoryAttribute("code")]
        [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
        [System.Xml.Serialization.XmlRootAttribute(ElementName = "xml", Namespace = "", IsNullable = false)]
        public class WxUnifiedOrderResponse
        {
            /// <summary>
            /// 返回状态码
            /// </summary>
            [XmlElement(ElementName = "return_code")]
            public string Return_Code { get; set; }
    
            /// <summary>
            /// 返回信息
            /// </summary>
            [XmlElement(ElementName = "return_msg")]
            public string Return_Msg { get; set; }
    
            /// <summary>
            /// 小程序id
            /// </summary>
            [XmlElement(ElementName = "appid")]
            public string Appid { get; set; }
    
            /// <summary>
            /// 商户号
            /// </summary>
            [XmlElement(ElementName = "mch_id")]
            public string Mch_Id{get;set;}
            /// <summary>
            /// 随机字符串
            /// </summary>
            [XmlElement(ElementName = "nonce_str")]
            public string Nonce_Str { get; set; }
            /// <summary>
            /// 
            /// </summary>
            [XmlElement(ElementName = "openid")]
            public string Openid { get; set; }
            /// <summary>
            /// 微信返回的签名
            /// </summary>
            [XmlElement(ElementName = "sign")]
            public string Sign { get; set; }
            /// <summary>
            /// 业务结果
            /// </summary>
            [XmlElement(ElementName = "result_code")]
            public string Result_Code { get; set; }
    
            /// <summary>
            /// 预支付交易回话标识
            /// </summary>
            [XmlElement(ElementName = "prepay_id")]
            public string Prepay_Id { get; set; }
            /// <summary>
            /// 交易类型
            /// </summary>
            [XmlElement(ElementName = "trade_type")]
            public string Trade_Type { get; set; }
        }
    View Code

    7,再次签名

    TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
                var wxPaidParams = new WxPaidParams()
                {
                    appId = unifiedOrder.Data.Appid,
                    nonceStr = unifiedOrder.Data.Nonce_Str,
                    package = string.Concat("prepay_id=", unifiedOrder.Data.Prepay_Id),
                    signType = "MD5",
                    timeStamp = Convert.ToInt64(ts.TotalSeconds).ToString()
                };
    
                var type = wxPaidParams.GetType();
                SortedDictionary<string, string> param = new SortedDictionary<string, string>();
                foreach (var item in type.GetProperties())
                {
                    if (item.GetValue(wxPaidParams) != null && item.Name != "paySign")
                    {
                        param.Add(item.Name, item.GetValue(wxPaidParams).ToString());
                    }
                }
                List<string> lstparams = new List<string>();
                foreach (var item in param)
                {
                    lstparams.Add(string.Concat(item.Key, "=", item.Value));
                }
                lstparams.Add(string.Concat("key", "=", _configuration["WechatPaied:Api_Key"]));
                string param_paySign = string.Join("&", lstparams);
                wxPaidParams.paySign = param_paySign.MD5().ToUpper();

    7.1  WxPaidParams

      public class WxPaidParams
        {
            /// <summary>
            /// appid
            /// </summary>
            public string appId { get; set; }
            /// <summary>
            /// 时间戳
            /// </summary>
            public string timeStamp { get; set; }
            /// <summary>
            /// 随机串
            /// </summary>
            public string nonceStr { get; set; }
            /// <summary>
            /// 数据包
            /// </summary>
            public string package { get; set; }
            /// <summary>
            /// 签名方式
            /// </summary>
            public string signType { get; set; }
            /// <summary>
            /// 签名
            /// </summary>
            public string paySign { get; set; }
        }
    View Code
    一毛一样,的道理,主逻辑写下来不到100行代码,将来统一下单地方的参数有变化,仅仅需要增加字段,赋值就可以,其他都不动,
    再把下边那坨加密的东西再稍微封装一下,用到生产环境妥妥的。

  • 相关阅读:
    python json 和 pickle的补充 hashlib configparser logging
    go 流程语句 if goto for swich
    go array slice map make new操作
    go 基础
    块级元素 行内元素 空元素
    咽炎就医用药(慢性肥厚性咽炎)
    春季感冒是风寒还是风热(转的文章)
    秋季感冒 咳嗽 怎么选药
    解决IE浏览器“无法显示此网页”的问题
    常用的 css 样式 记录
  • 原文地址:https://www.cnblogs.com/zzfstudy/p/13519051.html
Copyright © 2011-2022 走看看