微信支付V2 统一下单 .NET CORE
一个小功能总是拖拖拖。。唉。。。今天2024年01月15日终于调成功了,以下是代码,能取到预支付订单号就行了。。
2024年7月25日 再测试,好像之前的不行,还得再加上一步,还需要二次签名。。。
/// <summary> /// 微信支付-微信小程序 /// </summary> /// <returns></returns> [HttpGet("Wxpay_app")] public async Task<ApiResult> Wxpay_app(string wxappopenid) { try { if (string.IsNullOrEmpty(wxappopenid)) { throw new Exception("wxappopenid is null."); } //微信支付V2-统一下单文档 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1 //1.准备提交数据 Hashtable ht = new Hashtable(); ht.Add("appid", "wxd64fd8b6ce123486"); ht.Add("mch_id", "1628000000"); ht.Add("nonce_str", Guid.NewGuid().ToString().Replace("-", "")); ht.Add("sign_type", "MD5"); ht.Add("body", "腾讯充值中心-QQ会员充值"); ht.Add("out_trade_no", DateTime.Now.ToString("yyyyMMddHHmmss") + Guid.NewGuid().ToString().Substring(0, 4)); ht.Add("total_fee", 1); ht.Add("spbill_create_ip", HttpContext.UserHostAddress().ToString()); ht.Add("notify_url", "https://bbb.sss.net/api/wx/notify"); ht.Add("trade_type", "JSAPI"); ht.Add("openid", wxappopenid); //2.签名: 排序、拼接、MD5, 把生成的签名加入到提交数据的sign中 string pinjie = ""; string key = "keykeykey0123456789jccy"; SortedDictionary<string, string> sortedDictionary = new SortedDictionary<string, string>(); foreach (DictionaryEntry entry in ht) { sortedDictionary.Add(entry.Key.ToString(), entry.Value.ToString()); } foreach (KeyValuePair<string, string> pair in sortedDictionary) { if (string.IsNullOrEmpty(pair.Value)) { continue; } pinjie += $"{pair.Key}={pair.Value}&"; } pinjie += "key=" + key; _logger.LogInformation("拼接好的串:\r\n" + pinjie + "\r\n"); string sign = Tool.MD5Hash(pinjie).ToUpper(); ht.Add("sign", sign); //3.把提交的数据转为XML XmlDocument xmlDoc = new XmlDocument(); XmlElement rootElement = xmlDoc.CreateElement("xml"); xmlDoc.AppendChild(rootElement); foreach (DictionaryEntry entry in ht) { XmlElement element = xmlDoc.CreateElement(entry.Key.ToString()); element.InnerText = entry.Value.ToString(); rootElement.AppendChild(element); } string postdata = xmlDoc.OuterXml; _logger.LogInformation("提交的XML:\r\n" + postdata + "\r\n"); //4.把XML数据POST提交到微信支付V2的接口地址,得到返回的预支付订单号 string aaa = ""; string package = "prepay_id="; using (var client = new HttpClient()) { var content = new StringContent(postdata, Encoding.UTF8, "application/xml"); var response = await client.PostAsync("https://api.mch.weixin.qq.com/pay/unifiedorder", content); if (response.IsSuccessStatusCode) { aaa = await response.Content.ReadAsStringAsync(); _logger.LogInformation("远程返回:\r\n" + aaa + "\r\n"); if (aaa.Contains("FAIL")) { //失败 <result_code><![CDATA[FAIL]]></result_code> throw new Exception(aaa); } XDocument xdoc = XDocument.Parse(aaa); var ad = from a in xdoc.Descendants("xml") select new { return_code = a.Element("return_code").Value, return_msg = a.Element("return_msg").Value, appid = a.Element("appid").Value, mch_id = a.Element("mch_id").Value, nonce_str = a.Element("nonce_str").Value, sign = a.Element("sign").Value, result_code = a.Element("result_code").Value, prepay_id = a.Element("prepay_id").Value, trade_type = a.Element("trade_type").Value, }; var a1 = ad.FirstOrDefault(); if (a1.result_code == "SUCCESS" && a1.return_code == "SUCCESS") { package += a1.prepay_id; } else { throw new Exception(a1.return_msg); } } else { throw new Exception($"StatusCode: {response.StatusCode}"); } } //5.小程序调起微信支付还需要再进行二次签名 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=5 Hashtable ht_return = new Hashtable(); ht_return.Add("appId", ht["appid"]); ht_return.Add("timeStamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds()); ht_return.Add("nonceStr", ht["nonce_str"]); ht_return.Add("package", package); ht_return.Add("signType", ht["sign_type"]); string sign2 = Tool.MD5Hash($"appId={ht_return["appId"]}&nonceStr={ht_return["nonceStr"]}&package={ht_return["package"]}&signType={ht_return["signType"]}&timeStamp={ht_return["timeStamp"]}&key={key}").ToUpper(); ht_return.Add("paySign", sign2); return new ApiResult() { code = 0, msg = aaa, data = ht_return, }; } catch (Exception ex) { return new ApiResult() { code = 1, msg = "出错:" + ex.Message }; } }
注意MD5加密那里得用utf8,原来是ascii的总是签名错误
/// <summary> /// netcore下的实现MD5加密 /// </summary> /// <param name="str"></param> /// <returns></returns> public static string MD5Hash(string input) { using (var md5 = MD5.Create()) { var result = md5.ComputeHash(Encoding.UTF8.GetBytes(input)); //用Encoding.ASCII的话在微信支付V2那里的签名不匹配 var strResult = BitConverter.ToString(result); return strResult.Replace("-", ""); } }