微信支付詳解

1.爲何會有兩種JS方法能夠發起微信支付?

當你登錄微信公衆號以後,左邊有兩個菜單欄,一個是微信支付,一個是開發者中心。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

第二種方法僅僅是針對微信支付這個功能提供的。數組

也就是說,按照這兩種方法來進行微信支付,都是能夠的,可是兩種方法調用的方式和提供的參數不同。緩存

2.微信支付有v2和v3版本的區別?

這種區別,是相對於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版本的開發方式。

3.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加密,轉換成大寫,最後返回給前端。

這時,前端就能夠調用此接口了。

 

上面的圖,咱們省略第二步。

4.按照統一接口實現v3版本的微信支付。

在微信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 。

  1. 參考如下文檔獲取access_token(有效期7200秒,開發者必須在本身的服務全局緩存access_token):../15/54ce45d8d30b6bf6758f68d2e95bc627.html
  2. 用第一步拿到的access_token 採用http GET方式請求得到jsapi_ticket(有效期7200秒,開發者必須在本身的服務全局緩存jsapi_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi

按照獲取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&timestamp=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版本已經淘汰。

若是須要實現微信支付和其餘微信功能,那麼參考第四項。

裏面的坑不少:記住,參數名的大小寫要一致,不論是前端仍是後臺,在簽名時,只要大小寫不一致,就會出錯。

 

 

 

 

加油!

相關文章
相關標籤/搜索