時間:2018-4-22 16:42:19
微信支付是騰訊公司的支付業務品牌,它提供公眾號支付、掃碼支付、APP支付、刷卡支付等支付方式,并且還提供代金券、現金紅包、企業付款等營銷工具。微信支付結合微信公眾號,全面打通O2O生活消費領域,提供專業的互聯網+行業解決方案,是移動支付的首選。
2013年8月5日,微信5.0版本引入了微信支付功能。2015年6月1日,騰訊發布了“2015微信用戶數據報告”,報告稱微信支付用戶數達到4億左右,可見微信支付的發展速度非常驚人。
我有幸于2013年6月微信支付內測期間就開始接觸微信支付開發,親眼見證了微信支付的每一次成長。在此期間,有許多初學者向我咨詢微信支付開發。今天,我就來吐槽一下微信支付開發中的各種“坑”。
V2和V3差異大
微信支付接口現在分為V2版和V3版,2014年9月10日之前申請的為V2版,之后申請的為V3版。這兩個版本在功能和接口上都有很大差別,不能互用,開發時要特別注意這一點,否則可能會走很多彎路。
開發文檔混亂
微信公眾平臺開發者文檔位于http://mp.weixin.qq.com/wiki/,相信大家都比較熟悉,然而有意思的是,這里面唯獨沒有微信支付的接口文檔。微信支付的接口文檔要登錄微信公眾平臺才能看得到,如圖1所示。
圖1 微信支付接口文檔
噢,原來藏在這里,也不算難找嘛!然而,仔細觀察會發現這里沒有代金券、現金紅包、企業付款等接口的說明。如果要查看所有的微信支付接口文檔,需要去微信支付商戶平臺,訪問地址為https://pay.weixin.qq.com/wiki/doc/api/index.html,如圖2所示。
圖2 微信支付商戶平臺開發者文檔
簽名算法
為了保證數據安全,微信支付要求所有發送或接收的數據都必須經過簽名,相信不少開發者都在簽名算法上吃過虧。下面是生成簽名時的一些注意事項和經驗分享。
【參數按字典序排序】
需要特別注意的是,參數名嚴格區分大小寫,并且值為空的參數不參與簽名。最讓我記憶猶新的是開發“收貨地址共享接口”,調用接口需要傳遞的參數(appId、timeStamp和nonceStr)在簽名時都必須小寫。
至于參數按字典序排序,在Java中,可以采用SortedMap來實現,非常簡便,不建議開發者自己實現排序算法。
【MD5和SHA1算法】
在微信支付相關的接口中,“收貨地址共享接口”使用SHA1算法進行簽名,除此之外的其他接口都使用MD5算法進行簽名。對于大多數開發者而言,編寫SHA1和MD5算法是有一定難度的,雖然最終的實現代碼只有幾行。
在Java中,可以采用Apache Commons Codec工具包來實現標準的MD5和SHA-1,示例代碼如下:
String source = "簽名測試"; String md5 = DigestUtils.md5Hex(source); System.out.println("md5簽名結果:" + md5); String sha1 = DigestUtils.sha1Hex(source); System.out.println("sha1簽名結果:" + sha1);
說明:運行以上示例需要在工程中引入jar包commons-codec-1.9.jar。
另外,需要注意的是,在“收貨地址共享接口”中,官方給出的SHA1簽名示例的結果是錯誤的,這估計誤導了很多開多者,讓他們誤以為自己的簽名算法有誤。官方示例如下
經我測試,上述示例中SHA1簽名后的正確結果為:
雙向證書
首先,我們來簡單認識一下SSL證書、單向認證和雙向認證。
SSL證書是由受信任的數字證書頒發機構CA(如GlobalSign,WoSign),在驗證服務器身份后頒發的,具有服務器身份驗證和數據傳輸加密的功能。單向認證是指在SSL通信過程中,客戶端需要驗證服務器證書的合法性,而服務器端不對客戶端證書進行校驗。雙向認證是指在SSL通信過程中,客戶端需要驗證服務器證書的合法性,服務器端也需要驗證客戶端證書的合法性。
在微信支付開發中,申請退款、發放現金紅包、發放裂變紅包等接口需要用到商戶證書,微信服務器會驗證商戶證書的合法性。API證書文件可按以下路徑下載:
下載到API證書之后,該如何在程序中使用呢?這就需要使用KeyManagerFactory類和KeyStore類,在程序中設定客戶端使用的證書。核心代碼如下:
// 證書文件(微信商戶平臺-賬戶設置-API安全-API證書-下載證書) String keyStorePath = "D:/apiclient_cert.p12"; // 證書密碼(默認為商戶ID) String password = WxPayUtil.partner; // 實例化密鑰庫 KeyStore ks = KeyStore.getInstance("PKCS12"); // 獲得密鑰庫文件流 FileInputStream fis = new FileInputStream(keyStorePath); // 加載密鑰庫 ks.load(fis, password.toCharArray()); // 關閉密鑰庫文件流 fis.close(); // 實例化密鑰庫 KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); // 初始化密鑰工廠 kmf.init(ks, password.toCharArray()); // 創建SSLContext SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(kmf.getKeyManagers(), null, new SecureRandom()); // 獲取SSLSocketFactory對象 SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(requestUrl); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); conn.setRequestMethod(requestMethod); // 設置當前實例使用的SSLSocketFactory conn.setSSLSocketFactory(ssf); conn.setDoOutput(true); conn.setDoInput(true); conn.connect();
希望本篇文章能夠幫助開發者順利避開微信支付開發的各種“坑”,快速掌握微信支付接口的使用。
技術支持:保定云創網絡設計 Copyright © 2007-2020 保定云創網絡設計 版權所有 網站建設 冀ICP備17031073號