研究微信开发一年多了,每个新接口,都会第一时间进行研究。微信支付开放很久,一直没机会接触到支付接口,等了好久终于从朋友那儿搞到了接口,从此开始了我两天多的支付接口的研究。

 

拿到这个接口文档的第一个想法就是这也没什么难的嘛, 和支付宝、财付通、网银在线等一些传统接口的思路逻辑都是一样的,觉得差不多最多一个下午就可以搞定,结果第一步调用统一支付接口就给来了个下马威,不管怎么改,就一直返回签名错误。第一次遇到签名错误,首先想到的是应该是没有正确理解签名的生成规则,又从头看了几次签名的生成规则,每次都是的理解都是一样的,试了改几次还是不行。 这一次已经开始怀疑腾讯的文档写的有问题,一边找其他资料一边在心里骂腾讯写文档的作者。在园子里看到了到处都是坑的微信支付V3后,更加确认是微信的文档的问题。现在想想当时的想法太幼稚了,大部分自信心爆棚的人,在遇到解决不了的问题时总是会怀疑是不是别人给的东西不对,而不会从自身找问题,一句话总结就是一到便秘就怪地球没引力。(各位看官请勿对号入座,纯属个人见解,勿喷)。

现在说正题。。

从开始遇到错误到最后解决签名的问题,总结的问题就是我在生成签名的时候把参数进行了编码,而官方给的开发文档并没有说要做url编码,另外一个就是我进入了一个死胡同,总觉得自己的理解与实现过程没有问题,但最后当我把之前写的代码完全放弃,推倒重做后,问题终于解决。兴奋之极。下面从头说下我的理解与解决方法。

官方文档中接口调用规则:

�  认证方式:HTTPS 认证,退款和冲正接口调用需要商户证书(证书在审核邮件附件

中)

�  请求采用 POST 方式

�  提交和返回结果采用 XML 格式

�  字符集默认使用 UTF-8,请勿使用其它字符集

�  商户与微信之间的交互(特别是 Native 回调和支付通知回调),都需要验证签名

�  处理返回时先判断协议返回错误码,再判断业务返回错误码,最后判断交易状态

 

下面是官方的签名生成方法

a.对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)后,使用 URL 键值对的格式(即 key1=value1&key2=value2…)拼接成字符串 string1,注意:值为空的参数不参与签名

b. 在 string1 最 后 拼 接 上 key=Key( 商 户 支 付 密 钥 ) 得 到 stringSignTemp 字 符 串 , 并 对 stringSignTemp 进行 md5 运算,再将得到的字符串所有字符 转换为大写,得到 sign 值

下面是我所理解的签名生成规则:

1,所有的参数都是小写的

2,参数的值不需要做任何处理,包括url编码

3,确保必须的参数不能为空,且是正确无误的。

下面是示范过程:

要传入的参数分别为:appid,mch_id,nonce_str,body,attach,out_trade_no,total_fee,spbill_create_ip,notify_url,trade_type,openid(jsapi必须) ,product_id(native必须)。

首先将键值对存入 Dictionary<string,string>中,其次根据key值升序排序,代码如下:    var dictemp = dic.OrderBy(d => d.Key);

然后将键值对转换成url形式后,在末尾链接上key值,例如:appid=****&attach=****…………&key=******,最后进行md5加密并将加密后的字符串转换成大写。这里需要特别注意的是,md5加密是需要将字符集转换成utf-8,否则中文商品描述会出现乱码。

md5加密
 1  public static string MD5(string pwd)
 2         {
 3             MD5 md5 = new MD5CryptoServiceProvider();
 4             byte[] data = System.Text.Encoding.UTF8.GetBytes(pwd);
 5             byte[] md5data = md5.ComputeHash(data);
 6             md5.Clear();
 7             string str = "";
 8             for (int i = 0; i < md5data.Length; i++)
 9             {
10                 str += md5data[i].ToString("x").PadLeft(2, '0');
11             }
12             return str;
13         }

 

 

生成签名后将sign=签名  键值对添加到生成签名时生成的dictemp中,然后将dictemp转换成xml,post到https://api.mch.weixin.qq.com/pay/unifiedorder,返回值也是xml,最后对xml进行解析,为了保证安全性,需将解析后的键值对进行签名校验。

1 <xml><appid><![CDATA[******]]></appid><mch_id><![CDATA[******]]></mch_id><nonce_str><![CDATA[13120e01b82b48cfbebd4c9df66f0e47]]></nonce_str><body><![CDATA[神六]]></body><out_trade_no><![CDATA[ggggg673526]]></out_trade_no><total_fee><![CDATA[1000000]]></total_fee><spbill_create_ip><![CDATA[59.174.203.41]]></spbill_create_ip><notify_url><![CDATA[http://wxpay.ttyouni.net/aspx/order/notify.aspx]]></notify_url><trade_type><![CDATA[JSAPI]]></trade_type><openid><![CDATA[ozJkDj6yXuUsxIgS4xiJbtZMv2XQ]]></openid><sign><![CDATA[7CBA5A6BFF210BDA8C1AA33E9D803711]]></sign></xml>
正确的xml
<xml>
<
appid><![CDATA[******]]></appid>
<
mch_id><![CDATA[******]]></mch_id>
<
nonce_str><![CDATA[13120e01b82b48cfbebd4c9df66f0e47]]></nonce_str>
<
body><![CDATA[神六]]></body>
<
out_trade_no><![CDATA[ggggg673526]]></out_trade_no>
<
total_fee><![CDATA[1000000]]></total_fee>
<
spbill_create_ip><![CDATA[59.174.203.41]]></spbill_create_ip>
<
notify_url><![CDATA[http://wxpay.ttyouni.net/aspx/order/notify.aspx]]></notify_url>
<
trade_type><![CDATA[JSAPI]]></trade_type>
<
openid><![CDATA[ozJkDj6yXuUsxIgS4xiJbtZMv2XQ]]></openid>
<
sign><![CDATA[7CBA5A6BFF210BDA8C1AA33E9D803711]]></sign>
</
xml>

 

校验签名无误后,下一步就是取出预支付id prepay_id,然后调用微信支付js,注意:调用微信支付js之前也需要将所有参与调用的参数进行签名,且这里的参与签名的参数需要验证遵守大小写(腾讯有的时候真的很脑残,一会全小写,一会有大写有小写)。生成签名后就可以调用微信支付js了,代码如下:

 1 var WxPay= {
 2     Pay: function (appId, timeStamp, nonceStr, package, signType, paySign,callback) {
 3         WeixinJSBridge.invoke('getBrandWCPayRequest', {
 4             "appId": appId,    //公众号名称,由商户传入
 5             "timeStamp":timeStamp,    //时间戳,自 1970 年以来的秒数
 6             "nonceStr": nonceStr, //随机串
 7             "package": package,
 8             "signType": signType,    //微信签名方式
 9             "paySign": paySign //微信签名
10         }, function (res) {
11             if (res.err_msg == "get_brand_wcpay_request:ok") {
12                 callback();
13             }
14             // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg 将在用户支付成功后返回 ok,但并不保证它绝对可靠。
15         });
16     }
17 }
微信支付js
 1 var WxPay= {
 2     Pay: function (appId, timeStamp, nonceStr, package, signType, paySign,callback) {
 3         WeixinJSBridge.invoke('getBrandWCPayRequest', {
 4             "appId": appId,    //公众号名称,由商户传入
 5             "timeStamp":timeStamp,    //时间戳,自 1970 年以来的秒数
 6             "nonceStr": nonceStr, //随机串
 7             "package": package,
 8             "signType": signType,    //微信签名方式
 9             "paySign": paySign //微信签名
10         }, function (res) {
11             if (res.err_msg == "get_brand_wcpay_request:ok") {
12                 callback();
13             }
14             // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg 将在用户支付成功后返回 ok,但并不保证它绝对可靠。
15         });
16     }
17 }

 

为了方便调用,我将微信支付js写到了一个单独的js文件,然后在页面中载入,生成签名用ajax调用。调用代码如下:

 1 <script>
 2         $(function () {
 3             $("#submit").click(function () {
 4                 $.get("WxPay.ashx?action=jspayparam", {
 5                     body: $("#body").val(),
 6                     total_fee: $("#price").val(),
 7                     out_trade_no: $("#order").val(),
 8                     trade_type: "JSAPI",
 9                     msgid:"<%=openid%>"
10                 }, function (data) {
11                     WxPay.Pay(data.appId, data.timeStamp, data.nonceStr, data.package, data.signType, data.paySign, function () {
12                         alert("支付成功");
13                     });
14                 }, "json");
15 
16             });
17         })
18     </script>
支付js调用
 1 <script>
 2         $(function () {
 3             $("#submit").click(function () {
 4                 $.get("WxPay.ashx?action=jspayparam", {
 5                     body: $("#body").val(),
 6                     total_fee: $("#price").val(),
 7                     out_trade_no: $("#order").val(),
 8                     trade_type: "JSAPI",
 9                     msgid:"<%=openid%>"
10                 }, function (data) {
11                     WxPay.Pay(data.appId, data.timeStamp, data.nonceStr, data.package, data.signType, data.paySign, function () {
12                         alert("支付成功");
13                     });
14                 }, "json");
15 
16             });
17         })
18     </script>

 

相关文章:

  • 2021-09-11
  • 2021-06-09
  • 2022-12-23
  • 2021-08-18
  • 2022-01-20
  • 2021-07-22
  • 2021-07-08
猜你喜欢
  • 2021-12-09
  • 2021-06-26
  • 2022-01-04
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案