C#微信开发,避雷,防踩坑总结
作者:互联网
微信支付
1.首先下单接口,选择统一下单
微信统一下单接口:https://api.mch.weixin.qq.com/pay/unifiedorder
防踩雷:并不是JSAPI/小程序下单API https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
2.微信接口中请求参数需带随机数、签名、签名类型
- 2.1随机数
这是官网给出的
生成随机数算法
微信支付API接口协议中包含字段nonce_str,主要保证签名不可预测。我们推荐生成随机数算法如下:调用随机数函数生成,将得到的值转换为字符串。
16进制,32位随机生成的数
随机数算法代码:
public static String GetNonceStr()
{
String symbols = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
Random random = new SecureRandom();
char[] nonceChars = new char[32];
for (int index = 0; index < nonceChars.Length; ++index)
{
nonceChars[index] = Convert.ToChar(symbols.Substring((random.Next(symbols.Length)), 1));
}
return new String(nonceChars);
}
- 2.2签名
签名特别注意一下重要规则:
◆ 参数名ASCII码从小到大排序(字典序);
◆ 如果参数的值为空不参与签名;
◆ 参数名区分大小写;
◆ 验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
◆ 微信接口可能增加字段,验证签名时必须支持增加的扩展字段
按照官方给出的文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3
◆ 组合body参数
//设置package订单参数
SortedDictionary<string, string> dic = new SortedDictionary<string, string>();
dic.Add("appid", appid);
dic.Add("mch_id", StoreId);//财付通帐号商家
dic.Add("nonce_str", nonce_str);
dic.Add("trade_type", pay.tradeType());
dic.Add("attach", pay.attach());
dic.Add("openid", order.openid);
dic.Add("out_trade_no", order.out_trade_no); //商家订单号
dic.Add("total_fee", order.total_fee.ToString()); //商品金额,以分为单位(money * 100).ToString()
dic.Add("notify_url", pay.notify_url());//接收财付通通知的URL
dic.Add("body", pay.body());//商品描述
dic.Add("spbill_create_ip", pay.addrIp()); //用户的公网ip,不是商户服务器IP
string get_sign = BuildRequest(dic, StoreSecret); //进行加密
在这个步骤里面,sign不加入加密
◆ 加密方法
public static string BuildRequest(SortedDictionary<string, string> sParaTemp, string key)
{
//获取过滤后的数组
Dictionary<string, string> dicPara = new Dictionary<string, string>();
dicPara = FilterPara(sParaTemp);
//组合参数数组
string prestr = CreateLinkString(dicPara);
//拼接支付密钥
string stringSignTemp = prestr + "&key=" + key;
//获得加密结果
string myMd5Str = GetMD5(stringSignTemp);
//返回转换为大写的加密串
return myMd5Str.ToUpper();
}
◆ 通过ASCII码排序
/// <summary>
/// 除去数组中的空值和签名参数并以字母a到z的顺序排序
/// </summary>
/// <param name="dicArrayPre">过滤前的参数组</param>
/// <returns>过滤后的参数组</returns>
public static Dictionary<string, string> FilterPara(SortedDictionary<string, string> dicArrayPre)
{
Dictionary<string, string> dicArray = new Dictionary<string, string>();
foreach (KeyValuePair<string, string> temp in dicArrayPre)
{
if (temp.Key != "sign" && !string.IsNullOrEmpty(temp.Value))
{
dicArray.Add(temp.Key, temp.Value);
}
}
return dicArray;
}
◆ 组合参数数组
//组合参数数组
public static string CreateLinkString(Dictionary<string, string> dicArray)
{
StringBuilder prestr = new StringBuilder();
foreach (KeyValuePair<string, string> temp in dicArray)
{
prestr.Append(temp.Key + "=" + temp.Value + "&");
}
int nLen = prestr.Length;
prestr.Remove(nLen - 1, 1);
return prestr.ToString();
}
◆ MD5加密
//加密
public static string GetMD5(string pwd)
{
MD5 md5Hasher = MD5.Create();
byte[] data = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(pwd));
StringBuilder sBuilder = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
return sBuilder.ToString();
}
以上就是生成sign的方法
在拼接参数加入sing,post请求
string _req_data = "<xml>";
_req_data += "<appid><![CDATA[" + appid + "]]></appid>";
_req_data += "<mch_id><![CDATA[" + StoreId + "]]></mch_id> ";
_req_data += "<nonce_str><![CDATA[" + nonce_str + "]]></nonce_str> ";
_req_data += "<trade_type><![CDATA[" + pay.tradeType() + "]]></trade_type> ";
_req_data += "<attach><![CDATA[" + pay.attach() + "]]></attach>";
_req_data += "<openid><![CDATA[" + order.openid + "]]></openid> ";
_req_data += "<out_trade_no><![CDATA[" + order.out_trade_no + "]]></out_trade_no> ";
_req_data += "<total_fee><![CDATA[" + order.total_fee.ToString() + "]]></total_fee> ";
_req_data += "<notify_url><![CDATA[" + pay.notify_url() + "]]></notify_url> ";
_req_data += "<body><![CDATA[" + pay.body() + "]]></body> ";
_req_data += "<spbill_create_ip><![CDATA[" + pay.addrIp() + "]]></spbill_create_ip> ";
_req_data += "<sign><![CDATA[" + get_sign + "]]></sign> ";
_req_data += "</xml>";
var rsultStr = client.PostAsync(url, new StringContent(_req_data, Encoding.UTF8, "application/x-www-form-urlencoded")).Result.Content.ReadAsStringAsync().Result;
微信退款
微信退款参数如上。
退款接口需要接入双向证书,证书需要在微信商户平台里面下载
string path = Path.Combine("", "path");
var cer = new X509Certificate2(path, StoreId);
handler.ClientCertificates.Add(cer);
var clientPost = new HttpClient(handler);
var rsultStr = clientPost.PostAsync(url, new StringContent(_req_data, Encoding.UTF8, "application/x-www-form-urlencoded")).Result.Content.ReadAsStringAsync().Result;
微信服务通知
◆ 需要在商户平台,服务通知添加通知模板,拿到模板ID
string send_url = $"https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={body.access_token}";
character_string1 character_string1 = new character_string1()
{
value=body.sno
};
date2 date2 = new date2()
{
value = DateTime.Now.ToString("f")
};
Data data = new Data()
{
character_string1 = character_string1,
date2 = date2,
};
FromBody from = new FromBody()
{
access_token= body.access_token,
touser=body.touser,
page = "",
miniprogram_state = "formal",//developer为开发版;trial为体验版;formal为正式版;默认为正式版
template_id = "模板id",
data=data
};
var json = JsonConvert.SerializeObject(from);
var clientPost = new HttpClient();
var rsultStr = clientPost.PostAsync(send_url, new StringContent(json, Encoding.UTF8, "application/x-www-form-urlencoded")).Result.Content.ReadAsStringAsync().Result;
实体类
public class Data
{
public character_string1 character_string1 { get; set; }
public date2 date2 { get; set; }
}
public class character_string1
{
public string value { get; set; }
}
public class date2
{
public string value { get; set; }
}
标签:string,避雷,微信,req,dic,C#,Add,new,data 来源: https://www.cnblogs.com/supreme-fee/p/14247101.html