程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 坑爹的微信支付v3,其實沒有那麼坑,v3

坑爹的微信支付v3,其實沒有那麼坑,v3

編輯:C#入門知識

坑爹的微信支付v3,其實沒有那麼坑,v3


研究微信開發一年多了,每個新接口,都會第一時間進行研究。微信支付開放很久,一直沒機會接觸到支付接口,等了好久終於從朋友那兒搞到了接口,從此開始了我兩天多的支付接口的研究。

 

拿到這個接口文檔的第一個想法就是這也沒什麼難的嘛, 和支付寶、財付通、網銀在線等一些傳統接口的思路邏輯都是一樣的,覺得差不多最多一個下午就可以搞定,結果第一步調用統一支付接口就給來了個下馬威,不管怎麼改,就一直返回簽名錯誤。第一次遇到簽名錯誤,首先想到的是應該是沒有正確理解簽名的生成規則,又從頭看了幾次簽名的生成規則,每次都是的理解都是一樣的,試了改幾次還是不行。 這一次已經開始懷疑騰訊的文檔寫的有問題,一邊找其他資料一邊在心裡罵騰訊寫文檔的作者。在園子裡看到了到處都是坑的微信支付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,否則中文商品描述會出現亂碼。

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 } md5加密

 

生成簽名後將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

校驗簽名無誤後,下一步就是取出預支付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

為了方便調用,我將微信支付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調用

這裡我只傳入了一些和商品相關的參數,其他和商品無法的參數寫到了後台代碼中。後台收到請求後,將appid,mch_id等參數拼接成鍵值對進行進一步的處理,然後將處理後的結果返回給前台。

 

1 void GetJsPayParam(HttpContext context) 2 { 3 JsEntities jsEntities = new JsEntities() 4 { 5 appId = appid, 6 nonceStr = WxPayHelper.Utils.GetRandom(), 7 package = string.Format("prepay_id={0}", GetPrepayId(context)), 8 signType = "MD5", 9 timeStamp = WxPayHelper.Utils.ConvertDateTimeInt(DateTime.Now).ToString() 10 }; 11 string url, sign; 12 WxPayHelper.Utils.GetUnifyUrlXml<JsEntities>(jsEntities, key, out url, out sign); 13 jsEntities.paySign = sign; 14 context.Response.Write(JsonConvert.SerializeObject(jsEntities)); 15 } 獲取js支付參數

下面是生成鍵值對的方法,由於請求支付的過程中,到處需要生成簽名,所以我將各個請求參數都寫成了一個個類,然後使用泛型類和反射動態生成字典鍵值對,請求url和xml。代碼如下:

1 public static string GetUnifyUrlXml<T>(T t,string key,out string url,out string _sign) 2 { 3 Type type = typeof (T); 4 Dictionary<string,string> dic = new Dictionary<string, string>(); 5 PropertyInfo[] pis = type.GetProperties(); 6 #region 組合url參數到字典裡 7 foreach (PropertyInfo pi in pis) 8 { 9 object val = pi.GetValue(t, null); 10 if (val != null) 11 { 12 dic.Add(pi.Name, val.ToString()); 13 } 14 } 15 #endregion 16 //字典排序 17 var dictemp = dic.OrderBy(d => d.Key); 18 #region 生成url字符串 19 StringBuilder str = new StringBuilder(); 20 foreach (var item in dictemp) 21 { 22 str.AppendFormat("{0}={1}&", item.Key, item.Value); 23 } 24 #endregion 25 var ourl= str.ToString().Trim('&'); 26 //加上key 27 string tempsign = ourl + "&key="+key; 28 //md5加密後,轉換成大寫 29 string sign = MD5(tempsign).ToUpper(); 30 //將簽名添加到字典中 31 dic.Add("sign", sign); 32 _sign = sign; 33 url = str.AppendFormat("sign={0}",sign).ToString(); 34 //生成請求的內容,並返回 35 return parseXML(dic); 36 } 生成鍵值對,url,xml

  到這裡應該就可以滿足jsapi的需求了, 後期會將native和其他接口分享給大家。

 

 

 

 

如果你覺得本文對你有幫助,請大方的掃下面的二維碼懸賞一下吧。

新建了個微信支付及微信開發的QQ群,歡迎大家加入一起交流微信開發技術。217073730

 


微信彩票坑爹,退出理財通,退出微信支付垃圾

還要給她媽寫信
因為此刻的我心已枯竭
如果我感到口渴就別把海洋帶來。
我看見自己躺在那張古舊的竹椅
秋天從我手裡吃它的葉子:我們是朋友。
你摘下白晝中那頂脂粉的面具,歸真哈哈
 

dnf微信支付坑爹

這種東西它會給你解決麼 疼訊笑而不語 呵呵……
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved