當你登錄微信公衆號以後,左邊有兩個菜單欄,一個是微信支付,一個是開發者中心。javascript
在開發者中心中,有一個微信JS-SDK說明文檔。html
在此說明文檔中,有一個發起微信支付的請求API前端
wx.chooseWXPay({ timestamp: 0, // 支付簽名時間戳,注意微信jssdk中的全部使用timestamp字段均爲小寫。但最新版的支付後臺生成簽名使用的timeStamp字段名需大寫其中的S字符 nonceStr: '', // 支付簽名隨機串,不長於 32 位 package: '', // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=***) signType: '', // 簽名方式,默認爲'SHA1',使用新版支付需傳入'MD5' paySign: '', // 支付簽名 success: function (res) { // 支付成功後的回調函數 } });
在微信支付菜單欄中,有一個使用教程。裏面有一個使用JS API發起支付請求的小菜單。java
進入以後,裏面一個公衆號支付的菜單欄。在裏面,有一個H5調起支付API的頁面。web
它裏面發起一個支付的代碼是:算法
function onBridgeReady(){ WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId" : "wx2421b1c4370ec43b", //公衆號名稱,由商戶傳入 "timeStamp":" 1395712654", //時間戳,自1970年以來的秒數 "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //隨機串 "package" : "prepay_id=u802345jgfjsdfgsdg888", "signType" : "MD5", //微信簽名方式: "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信簽名 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) {} // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返回 ok,但並不保證它絕對可靠。 } ); } if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onBridgeReady); } }else{ onBridgeReady(); }
爲何JS有兩種方法能夠調起微信支付呢?json
個人理解:第一種方法是爲了跟其餘js API接口統一(裏面能夠調用不少微信的功能)而提供的。api
第二種方法僅僅是針對微信支付這個功能提供的。數組
也就是說,按照這兩種方法來進行微信支付,都是能夠的,可是兩種方法調用的方式和提供的參數不同。緩存
這種區別,是相對於getBrandWCPayRequest方法發起的微信支付。
當你登錄微信公衆平臺,點擊微信支付。若是看到有技術升級的菜單欄,就證實你如今使用的是v2版本,若是你進行技術升級,那麼,就會升級到v3版本。
v2版本和v3版本的發起微信支付的方式不同,所以,若是你以前使用了v2版本進行了微信支付的開發,那麼你技術升級到v3版本後,就不能使用原來的v2版本的調用方式了,也就意味着,你的代碼須要改動。固然,你不升級的話,是沒有問題的。
v3版本比v2版本多了一些功能,好比:紅包,券等。
v2版本發起微信支付的方法:
WeixinJSBridge.invoke('getBrandWCPayRequest',{ "appId" : getAppId(), //公衆號ID "timeStamp" : getTimeStamp(), //時間戳,當前系統的時間,具體格式,請看API "nonceStr" : getNonceStr(), //隨機串,具體格式請看API "package" : getPackage(),//擴展包 "signType" : "SHA1", //微信簽名方式:sha1 "paySign" : getSign() //微信簽名 },function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) {} // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返回ok,但並不保證它絕對可靠。 //所以微信團隊建議,當收到ok返回時,向商戶後臺詢問是否收到交易成功的通知,若收到通知,前端展現交易成功的界面;若此時未收到通知,商戶後臺主動調用查詢訂單接口,查詢訂單的當前狀態,並反饋給前端展現相應的界面。 } );
v3版本發起微信支付的方法跟v2的同樣,只是參數不同。
其中,package的值,v3是經過統一接口調用獲取到的。
signType,v3使用的是md5方式。
因爲微信支付開發教程,已經按照v3版本的方式給出了,因此v2版本,咱們就不說了,接下來,咱們詳細講解v3版本的開發方式。
想要在前端發起微信支付,就必須有appId,timeStamp,nonceStr,package,signType,paySign這六個參數。
其中,appid,signType已經直接給出了。
timestamp和noncestr,能夠根據文檔給出的規則算出來。
package是統一下單接口返回的prepay_id參數值,提交格式如:prepay_id=***。
因此,咱們先來看下如何得到此prepay_id。
咱們先去看統一下單接口:
此接口的調用,是經過服務端的代碼進行調用的,也就是你的應用服務器,這裏咱們假設你使用的是java代碼。
URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder
appid,mch_id,nonce_str,body,out_trade_no,total_fee,notify_url,trade_type,這幾個參數,咱們能夠直接得到。
spbill_create_ip(終端IP)和sign(簽名)咱們須要採起方式得到。
獲取用戶的ip地址,前端能夠經過如下方式獲取,而後傳給後臺。後臺也能夠本身獲取(對java不熟)。
<script src="http://pv.sohu.com/cityjson?ie=utf-8"></script> var returnCitySN = {"cip": "210.21.236.135", "cid": "440300", "cname": "廣東省深圳市"};
最後,只剩下sign了。
咱們進入到簽名算法文檔。你們認真仔細的查看此文檔,由於此簽名算法會使用幾回。
此文檔中有一個例子,你們按照此例子把本身要請求的參數按照字典序組裝起來,最後拼接API祕鑰。此祕鑰是在商戶平臺中,帳戶設置,API安全中本身設置的,此祕鑰只能放在服務器端,也就是java代碼中,不能進行傳輸。以前的v2版本,就是放在前端(js代碼中的),不安全。
最後,用java代碼中的md5方法進行加密,加密完以後,轉化成大寫,就獲得sign了。
最後,經過java代碼,把這些參數組成xml文件發給微信服務器(https://api.mch.weixin.qq.com/pay/unifiedorder)。
若是返回成功,就會獲得如下這種形式的數據:
<xml> <return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> <appid><![CDATA[wx2421b1c4370ec43b]]></appid> <mch_id><![CDATA[10000100]]></mch_id> <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str> <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign> <result_code><![CDATA[SUCCESS]]></result_code> <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id> <trade_type><![CDATA[JSAPI]]></trade_type> </xml>
java代碼解析後,把prepay_id返回給前端。
這時,前端要發起微信支付,就只差paySign了。
此paySign,也必須按照簽名算法來獲得。這裏,咱們一樣在java代碼中,按照調起微信支付getBrandWCPayRequest方法的請求參數進行簽名算法操做。
這裏須要對appId,timeStamp,nonceStr,package,signType這5個請求參數進行組裝,而後拼接商戶平臺祕鑰,md5加密,轉換成大寫,最後返回給前端。
這時,前端就能夠調用此接口了。
上面的圖,咱們省略第二步。
在微信js-sdk中,有詳細的說明:全部須要使用JS-SDK的頁面必須先注入配置信息,不然將沒法調用(同一個url僅需調用一次,對於變化url的SPA的web app可在每次url變化時進行調用,目前Android微信客戶端不支持pushState的H5新特性,因此使用pushState來實現web app的頁面會致使簽名失敗,此問題會在Android6.2中修復)。
wx.config({ debug: true, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。 appId: '', // 必填,公衆號的惟一標識 timestamp: , // 必填,生成簽名的時間戳 nonceStr: '', // 必填,生成簽名的隨機串 signature: '',// 必填,簽名,見附錄1 jsApiList: [] // 必填,須要使用的JS接口列表,全部JS接口列表見附錄2 });
這裏的參數,咱們只有signature不知道。
生成signature以前必須先了解一下jsapi_ticket,jsapi_ticket是公衆號用於調用微信JS接口的臨時票據。正常狀況下,jsapi_ticket的有效期爲7200秒,經過access_token來獲取。因爲獲取jsapi_ticket的api調用次數很是有限,頻繁刷新jsapi_ticket會致使api調用受限,影響自身業務,開發者必須在本身的服務全局緩存jsapi_ticket 。
按照獲取access token的文檔,咱們能夠得到
{"access_token":"ACCESS_TOKEN","expires_in":7200}
此文檔很容易看懂,AppID和AppSecret在微信公衆平臺可獲取。
緊接着第二步,就能夠得到:
{ "errcode":0, "errmsg":"ok", "ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA", "expires_in":7200 }
裏面的ticket就是jsapi_ticket。
最後,按照下面的簽名算法獲得signature。
簽名算法 簽名生成規則以下:參與簽名的字段包括noncestr(隨機字符串), 有效的jsapi_ticket, timestamp(時間戳), url(當前網頁的URL,不包含#及其後面部分) 。對全部待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)後,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1。這裏須要注意的是全部參數名均爲小寫字符。對string1做sha1加密,字段名和字段值都採用原始值,不進行URL 轉義。 即signature=sha1(string1)。 示例: noncestr=Wm3WZYTPz0wzccnW jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg timestamp=1414587457 url=http://mp.weixin.qq.com?params=value 步驟1. 對全部待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)後,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1: jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value 步驟2. 對string1進行sha1簽名,獲得signature: 0f9de62fce790f9a083d5c99e95740ceb90c27ed 注意事項 簽名用的noncestr和timestamp必須與wx.config中的nonceStr和timestamp相同。 簽名用的url必須是調用JS接口頁面的完整URL。 出於安全考慮,開發者必須在服務器端實現簽名的邏輯。 如出現invalid signature 等錯誤詳見附錄5常見錯誤及解決辦法。
配置完成以後,咱們就能夠在下面的函數中調用微信支付接口了。
wx.ready(function(){
wx.chooseWXPay({ timestamp: 0, // 支付簽名時間戳,注意微信jssdk中的全部使用timestamp字段均爲小寫。但最新版的支付後臺生成簽名使用的timeStamp字段名需大寫其中的S字符 nonceStr: '', // 支付簽名隨機串,不長於 32 位 package: '', // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=***) signType: '', // 簽名方式,默認爲'SHA1',使用新版支付需傳入'MD5' paySign: '', // 支付簽名 success: function (res) { // 支付成功後的回調函數 } });
// config信息驗證後會執行ready方法,全部接口調用都必須在config接口得到結果以後,config是一個客戶端的異步操做,因此若是須要在頁面加載時就調用相關接口,則須把相關接口放在ready函數中調用來確保正確執行。對於用戶觸發時才調用的接口,則能夠直接調用,不須要放在ready函數中。
});
而後,這裏的支付簽名paySign和package按照前面的方式得來就好了。
總結:若是僅僅是實現微信支付這樣的功能,仍是參考第三項。由於第四項多了一步,v2版本已經淘汰。
若是須要實現微信支付和其餘微信功能,那麼參考第四項。
裏面的坑不少:記住,參數名的大小寫要一致,不論是前端仍是後臺,在簽名時,只要大小寫不一致,就會出錯。
加油!