C#,微信小程序支付接口

最近有个项目涉及微信小程序支付功能,这里小墨将一些需要注意的地方已经实现步骤记录下来,给有需要的朋友

1、前期准备

需要提前准备好【全局变量】

public static string _appid = "xxxxxxxx";//appid
public static string appsecret = "xxxxxxxxx";//小程序密钥
public static string _mch_id = "xxxxxx";//商户号
public static string _key = "xxxxxxxxxxxxxxx";//商户平台设置的密钥key

这里可以找公司要,一般会提供,自己开发的话可以去微信公众平台申请,入口:  https://mp.weixin.qq.com

       //模拟wx统一下单 openid(前台获取)
        public string getda(dynamic _)
        {
            wx_parameter req = this.Bind<wx_parameter>();//这里是小程序传递的参数
            //支付费用
            double  total_fee =double.Parse(req.total_fee);//支付金额
            //获取openid
            var authorizeList = xx.GetList(new { applet_token = token }.ToJson()).ToList();
            var user = xxx.GetList(new { open_id = authorizeList[0].openid }.ToJson()).ToList()[0];
            string openid = user.open_id; //获取openid的方法可以百度下,https://www.cnblogs.com/dujian123/p/11184781.html

            return Getprepay_id(_appid, "shanghaifendian", "monixiaofei", _mch_id, GetRandomString(30), "http://www.weixin.qq.com/wxpay/pay.php", openid, getRandomTime(), total_fee);
        }

获取openid:https://www.cnblogs.com/dujian123/p/11184781.html

   /// <summary>
        /// 微信统一下单获取prepay_id & 再次签名返回数据
        /// 屡一下思路:通过参数请求统一下单的链接,返回的xml解析后,判断成功后,进行二次签名,最终返回给小程序前端。
        /// </summary>
        /// <param name="appid">appid</param>
        /// <param name="attach">附加数据(描述)</param>
        /// <param name="body">商品描述</param>
        /// <param name="mch_id">商户号</param>
        /// <param name="nonce_str">随机字符串,不长于32位。  </param>
        /// <param name="notify_url">通知地址</param>
        /// <param name="openid">openid</param>
        /// <param name="bookingNo">商户订单号</param>
        /// <param name="total_fee">支付金额单位为(分)比如一元等于100分</param>
        /// <returns></returns>
        private static string Getprepay_id(string appid, string attach, string body, string mch_id, string nonce_str, string notify_url, string openid, string bookingNo, double total_fee)
        {
            var url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信统一下单请求地址
            string strA = "appid=" + appid + "&attach=" + attach + "&body=" + body + "&mch_id=" + mch_id + "&nonce_str=" + nonce_str + "&notify_url=" + notify_url + "&openid=" + openid + "&out_trade_no=" + bookingNo + "&spbill_create_ip=61.50.221.43&total_fee=" + total_fee + "&trade_type=JSAPI";
            string strk = strA + "&key=" + _key;  //key为商户平台设置的密钥key(假)
            string strMD5 = MD5(strk).ToUpper();//MD5签名
            //string strHash=HmacSHA256("sha256",strmd5).ToUpper();   //签名方式只需一种(MD5 或 HmacSHA256     【支付文档需仔细看】)
            //签名
            //终端ip  
            string spbill_create_ip = getspbill_create_ip();
            var formData = "<xml>";
            formData += "<appid>" + appid + "</appid>";//appid  
            formData += "<attach>" + attach + "</attach>"; //附加数据(描述)
            formData += "<body>" + body + "</body>";//商品描述
            formData += "<mch_id>" + mch_id + "</mch_id>";//商户号  
            formData += "<nonce_str>" + nonce_str + "</nonce_str>";//随机字符串,不长于32位。  
            formData += "<notify_url>" + notify_url + "</notify_url>";//通知地址
            formData += "<openid>" + openid + "</openid>";//openid
            formData += "<out_trade_no>" + bookingNo + "</out_trade_no>";//商户订单号    --待
            formData += "<spbill_create_ip>"+ spbill_create_ip + "</spbill_create_ip>";//终端IP  --用户ip
            formData += "<total_fee>" + Convert.ToInt32(total_fee * 100).ToString() + "</total_fee>";//支付金额单位为(分)
            formData += "<trade_type>JSAPI</trade_type>";//交易类型(JSAPI--公众号支付)
            formData += "<sign>" + strMD5 + "</sign>"; //签名
            formData += "</xml>";
   
            //请求数据
            var getdata = sendPost(url, formData);
   
            //获取xml数据
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(getdata);
            wx w = new wx();
            if (doc != null)
            {
                XmlNode xmlNode = doc["xml"];
                if (xmlNode["return_code"].InnerText.Equals("SUCCESS") && xmlNode["result_code"].InnerText.Equals("SUCCESS"))
                {
                    #region 再次签名
                    //时间戳
                    string _time = getTime().ToString();
                    //prepay_id
                    string prepay_id = xmlNode["prepay_id"].InnerText;
                    //再次签名返回数据至小程序
                    string strB = "appId=" + appid + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id + "&signType=MD5&timeStamp=" + _time + "&key=" + _key;

                    w.Result = "Success";
                    w.errmsg = "统一下单成功";
                    w.timeStamp = _time;
                    w.nonceStr = nonce_str;
                    w.package = "prepay_id=" + prepay_id;
                    w.paySign = MD5(strB).ToUpper(); ;
                    w.signType = "MD5";
                    //向小程序返回json数据
                    #endregion
                }
                else
                {
                    w.Result = "Error";
                    w.errmsg = xmlNode["return_msg"].InnerText;
                }
            }
            else
            {
                w.Result = "Error";
                w.errmsg ="统一下单失败";
            }      
            return JsonConvert.SerializeObject(w);
        }

生成随机字符串以及签名加密的方法可以参考下面

      /// <summary>
      /// 生成随机串    
      /// </summary>
      /// <param name="length">字符串长度</param>
      /// <returns></returns>
      private static string GetRandomString(int length)
      {
          const string key = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
          if (length< 1)
              return string.Empty;
 
          Random rnd = new Random();
          byte[] buffer = new byte[8];
 
          ulong bit = 31;
          ulong result = 0;
          int index = 0;
          StringBuilder sb = new StringBuilder((length / 5 + 1) * 5);
 
          while (sb.Length<length)
          {
              rnd.NextBytes(buffer);
 
              buffer[5] = buffer[6] = buffer[7] = 0x00;
              result = BitConverter.ToUInt64(buffer, 0);
 
              while (result > 0 && sb.Length<length)
              {
                  index = (int) (bit & result);
                  sb.Append(key[index]);
                  result = result >> 5;
              }
          }
          return sb.ToString();
      }

        /// <summary>
        /// 获取终端ip,访问者ip
        /// </summary>
        /// <param name="_"></param>
        /// <returns></returns>
        private static string  getspbill_create_ip()
        {
            string url = "https://pv.sohu.com/cityjson?ie=utf-8";
            using (var httpClient = new HttpClient())
            {
                httpClient.DefaultRequestHeaders.Add("Accept", "application/json");//设置请求头
                var url1 = new Uri(url);
                // response
                var response = httpClient.GetAsync(url1).Result;
                var data = response.Content.ReadAsStringAsync().Result.Trim('"');
                data = data.TrimEnd(';').Split('=')[1].ToString();
                JObject obj = (JObject)JsonConvert.DeserializeObject(data);
                string spbill_create_ip = obj["cip"].ToString();
                return spbill_create_ip;
            }
        }

        /// <summary>
        /// 获取时间戳,时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间
        /// </summary>
        /// <returns></returns>
        private static long getTime()
       {
           TimeSpan cha = (DateTime.Now - TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)));
           long t = (long)cha.TotalSeconds;
           return t;
       }
     /// <summary>
    /// MD5签名方法  
    /// </summary>  
    /// <param name="inputText">加密参数</param>  
    /// <returns></returns>  
    private static string MD5(string inputText)
       {
           MD5 md5 = new MD5CryptoServiceProvider();
           byte[] fromData = System.Text.Encoding.UTF8.GetBytes(inputText);
           byte[] targetData = md5.ComputeHash(fromData);
           string byte2String = null;

           for (int i = 0; i<targetData.Length; i++)
           {
               byte2String += targetData[i].ToString("x2");
           }
           return byte2String;
        }
      /// <summary>
        /// HMAC-SHA256签名方式
        /// </summary>
        /// <param name="message"></param>
        /// <param name="secret"></param>
        /// <returns></returns>
        private static string HmacSHA256(string message, string secret)
        {
            secret = secret ?? "";
            var encoding = new System.Text.UTF8Encoding();
            byte[] keyByte = encoding.GetBytes(secret);
            byte[] messageBytes = encoding.GetBytes(message);
            using (var hmacsha256 = new HMACSHA256(keyByte))
            {
                byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
                return Convert.ToBase64String(hashmessage);
            }
        }


    /// <summary>
        /// wx统一下单请求数据
        /// </summary>
        /// <param name="URL">请求地址</param>
        /// <param name="urlArgs">参数</param>
        /// <returns></returns>
        private static string sendPost(string URL, string urlArgs)
        {
            System.Net.WebClient wCient = new System.Net.WebClient();
            wCient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
            //byte[] postData = System.Text.Encoding.ASCII.GetBytes(urlArgs);  如果微信签名中有中文会签名失败
        byte[] postData = System.Text.Encoding.UTF8.GetBytes(urlArgs);     
            byte[] responseData = wCient.UploadData(URL, "POST", postData);
            string returnStr = System.Text.Encoding.UTF8.GetString(responseData);//返回接受的数据 
            return returnStr;
         }


    /// <summary>
    /// 生成订单号【这里可以用一个订单表记录订单号】
    /// </summary>
    /// <returns></returns>
    private static string getRandomTime()
      {
          Random rd = new Random();//用于生成随机数
          string DateStr = DateTime.Now.ToString("yyyyMMddHHmmssMM");//日期
          string str = DateStr + rd.Next(10000).ToString().PadLeft(4, '0');//带日期的随机数
          return str;
      }

下面是所需要的实体类:

    /// <summary>
    /// 小程序调用后台
    /// </summary>
    public class wx_parameter
    {
        /// <summary>
        /// 支付费用
        /// </summary>
        public string total_fee { get; set; }
      
    }
    /// <summary>
    /// 返回给小程序
    /// </summary>
    public class wx
    {
        /// <summary>
        /// 返回结果【Success/Error】
        /// </summary>
        public string Result { get; set; }
        /// <summary>
        /// 描述
        /// </summary>
        public string errmsg { get; set; }

        /// <summary>
        /// 时间戳
        /// </summary>
        public string  timeStamp { get;set;}
        /// <summary>
        /// 随机数
        /// </summary>
        public string nonceStr { get; set; }
        /// <summary>
        /// 同一下单接口的prepay_id参数
        /// </summary>
        public string package { get; set; }
       /// <summary>
       /// 第二次签名
       /// </summary>
        public string paySign { get; set; }
       /// <summary>
       /// 签名方式
       /// </summary>
        public string signType { get; set; }

    }

最后需要做一个回调,用于支付成功后修改订单号状态等等(根据自己业务需求来)

下面是一些参考文档:

《微信官方文档:支付部分》

https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=3_1

扫描二维码关注公众号,回复: 12932230 查看本文章

《微信官方文档:统一支付》

https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1

有兴趣的可以关注“墨水直达”,里面有许多免费的编程资料可以领取哦~

猜你喜欢

转载自blog.csdn.net/huxinyu0208/article/details/109183196