JS-SDK微信支付開發攻略


 

  一、吐槽篇

  一個字——坑!兩個字——很坑!三個字——非常坑!首先,微信支付接口作為微信開發接口的一部分,竟然有一本書那么厚的官方文檔,共36頁,更重要的是,這36頁還不能把開發的流程說清楚,描述過於分散,過度分類,導致遇到一個問題的時候很難定位,雖然文檔前面給了時序圖,但是開發流程的時序化仍然不夠,讓人覺得十分混亂。本來接手這個任務的時候時間就非常的緊,想着找個demo撐死一兩天就完事了,沒想到最終耗費了接近一個星期,除去中間別的事耽誤的時間也用了整整五天的時間,在網上查找資料的時候也看到很多人說一個問題卡好幾天甚至幾周的情況,實在是難以接受。

  二、開發流程

  我這里就一並按順序總結了。首先我用的是JS-SDK,即官方文檔所描述的方式去做,必須說明的是,雖然是JS-SDK,但是整個簽名過程不可能只在JS里完成,由於安全性問題,微信提供的接口JS是無法跨域調用的,必須在后台進行調用再將結果發給前台。OK,我的開發的宏觀情況是,前端使用JS-SDK,后端使用JAVA tomcat。

  總體流程是:①授權部分:后端通過微信接口拿到access_token,再拿到ticket(jsapi_ticket),給前台,前台通過js-sdk將jsapi_ticket,noncestr,timestamp,url簽名,獲取授權。

        ②支付部分:前端獲取code,給后端,后端通過code訪問微信接口拿到openid,通過openid等一堆key信息和回調url拿到prepayid,把prepayid,timestamp,noncestr給前台,前台通把這些東西以及簽名提交,發起支付。

        ③回調部分:支付成功后,支付部分填寫的url的對應方法會執行,拿到后從參數中拿到支付成功后的信息,校驗簽名,發送成功結果給支付發起端。

        ④完成部分:前端收到成功的消息,自定義跳轉頁面。

  1、授權部分

  js部分:

  wx.config({

    debug: true, // 開啟調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時才會打印。
    appId: '', // 必填,公眾號的唯一標識
    timestamp: , // 必填,生成簽名的時間戳
    nonceStr: '', // 必填,生成簽名的隨機串
    signature: '',// 必填,簽名,見附錄1
    jsApiList: ["chooseWXPay"] // 必填,需要使用的JS接口列表,所有JS接口列表見附錄2
});

這是發起授權申請的部分,signature需要簽名的字段包括:
 "jsapi_ticket="+ticket+"&noncestr="+noncestr+"&timestamp="+timestamp+"&url="+url;
 
        
說明:
①jsapi_ticket獲取:
需要調用接口獲取,調用接口不能用js(跨域),所以在后台進行,接口調用使用https://api.weixin.qq.com/cgi-bin/ticket/getticket,GET方法即可,參數是"access_token="+access_token +"&type=JSAPI"
access_token獲取:
調用https://api.weixin.qq.com/cgi-bin/token,同樣使用GET方法,參數是"appid="+appid+"&secret="+secret+"&grant_type=client_credential",只要參數不錯,就能拿到jsapi_ticket了。
(后面獲取opendid的時候也會拿到一個
access_token,但不是同一個!)
③nonceStr、timestamp在JS生成即可,記得簽名時候的timestamp和nonceStr要和參數填寫的一樣。
④簽名規則:
就是在上面那一串東西后面加上"&key=xxxx",然后MD5加密處理后,變成大寫,key是商戶的key,千萬別搞錯了,不是appkey。規則具體看這里
⑤appId,這里I是大寫的
⑥url的獲取:
這個url不需要urlencode,但是必須是當前發起支付頁的url,若url中有#號,只取#前面的。下面代碼直接拿走吧!
location.href.split("#")[0]
 
        

⑦invalid signature:如⑥所說,url輸入的不對,url要動態獲取

⑧invalid url domain :url和appid沒綁定,要在微信公眾號那里的功能配置里配置,別把安全域名和業務域名搞混了……(我就在這里卡了半天)


配置成功后,就會進入
wx.ready(function(){
}
這個函數里面,並且如果debug打開,能看到configok的反饋。

  2、支付部分
為了確保wx.config成功后再支付(否則不可能支付),請把下面函數放到wx.ready里面:
wx.chooseWXPay({
    timestamp: 0, // 支付簽名時間戳,注意微信jssdk中的所有使用timestamp字段均為小寫。但最新版的支付后台生成簽名使用的timeStamp字段名需大寫其中的S字符
    nonceStr: '', // 支付簽名隨機串,不長於 32 位
    package: '', // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=***)
    signType: '', // 簽名方式,默認為'SHA1',使用新版支付需傳入'MD5'
    paySign: '', // 支付簽名
    success: function (res) {
        // 支付成功后的回調函數
    }
});
首先說明填寫要怎么填,別的應該都好理解,package這個東西有點不明所以,這個東西官方文檔叫做擴展包,但是在整個官方文檔里卻又找不到擴展包要填什么,只知道肯定要填"package=prepay_id=xxxx",我翻查了舊版微信支付的demo等,知道了這個擴展包主要是填寫一些選填的東西,例如幣種、編碼等,但這並不是必須的,用最簡單的"package=prepay_id=xxxx"填寫就可以了。
先給出要簽名的字符串列表
String signstr = "appid="+appid+"&body="+body+"&mch_id="+mch_id+"&nonce_str="+nonce_str+"&notify_url="+ notify_url +"&openid="+openid+"&out_trade_no="+out_trade_no+"&spbill_create_ip="+spbill_create_ip+"&total_fee="+total_fee+"&trade_type=JSAPI"+"&key="+appkey;

說明

①簽名必須在后端完成,前端timestamp和nonceStr必須和后端簽名時用的值一致。

②notify_url不需要urlencode,回調地址最好不要加參數(回調地址是支付成功后通知的那個地址接口,接口內容自己完成)

③openid的獲取:

可以看官方文檔,這些文檔都不是一個文檔,所以很容易找不到。

具體做法:

首先,在客戶端點擊支付后,必須先跳轉到這個地址:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

1)redirect_uri,是你使用JS-SDK的頁面的地址,也就是wx.chooseWXPay所在頁面的地址,必須進行urlencode,跳轉過去后能在url中尾部看到?code=CODE&state=STATE,把CODE從url中取出來。
2)使用GET方法調用這個接口https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code,把剛取到的code填進去,還有別的參數不要填錯了。
3) 返回的json格式中就能取到openid了。

④prepayid的獲取:
這部分仍然在后台進行,使用post並且是XML格式
發送數據,也就是說發送一段XML格式的字符串就是了,格式如下:
         String text = "<xml>"+
        "<appid>"+appid+"</appid>"+
         "<body>"+body+"</body>"+
         "<mch_id>"+mch_id+"</mch_id>"+
        " <nonce_str>"+nonce_str+"</nonce_str>"+
        " <notify_url>"+notify_url+"</notify_url>"+
         "<openid>"+openid+"</openid>"+
         "<out_trade_no>"+out_trade_no+"</out_trade_no>"+
         "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+
         "<total_fee>"+total_fee+"</total_fee>"+
         "<trade_type>"+"JSAPI"+"</trade_type>"+
         "<sign>"+sign+"</sign>"+
      "</xml>";

說明:

1)spbill_create_ip是支付終端的IP地址

2)notify_url不用urlencode

3)total_fee不能是小數,因為單位是分

4)簽名上面已經給了,就是用key,value方式把除了sign以外的所有字符串連起來,最后加上"&key=xxx",然后MD5再轉大寫。

5)out_trade_no,這個是自己標記自己商品號的一個號,不能重復,所以建議用時間戳+一些自己的規則。

6)body是中文時報簽名錯誤:首先確保中文是utf-8,然后轉成iso8859-1,可以用下面這句代碼:

text = new String(text.getBytes(), "iso8859-1");

注意:①假如是自己在本地調用接口,寫死一個中文去測試,請確保你的頁面編碼是utf-8,像我這種不太注意的,本來頁面用了GBK編碼,所以怎么試都不成功,怎么查編輯文件用什么編碼,自行谷歌百度自己的編輯器的設置編碼在哪里。

     ②tomcat的編碼,如果是從ajax把中文的body傳到后台,請注意tomcat的編碼設置,確保拿到的中文是utf-8。

7)上面的做好了,就可以拿到prepayid了,將prepayid和自己生成的nocestr和timestamp以及剛才生成的簽名sign傳回給前台,並且填到wx.chooseWXPay里,嘗試支付。

8)“商戶簽名錯誤”:假如已經拿驗算工具查過,簽名是正確的,仍然報錯,那必然是這個原因——timeStamp,S是大寫的!!。雖然官網已經做出了提醒,但是繞了那么多圈之后你早就不記得這件事了,或者說沒搞清楚,沒錯,簽名的時候timeStamp的S必須是大寫的,然后前台的wx.chooseWXPay里的timestamp是小寫的,就是那么的神奇!

9)當前的頁面URL未注冊:

微信公眾賬戶里的微信支付-支付測試,看看填寫的地址是不是支付所在的地址。

10)系統繁忙,正在升級,請稍后再試:

基本上不會是系統繁忙,這是我整個過程遇到微信接口唯一的一次報錯錯誤,請檢查簽名參數,着重檢查中文編碼問題。

 

 
        
3、支付部分
終於,突過重重難關,彈出支付圖標並且可以支付了,但是怪並沒有打完,你的回調接口可能還沒完善,這篇文章對回調部分的描述挺不錯的,網上能下到JAVA的DEMO,但有些部分已經不能用了,主要不能用的部分是拿到數據的時候需要用inputstream去處理,而不能通過request直接讀取。
回調要要做的事:
①拿到反饋數據
只要支付成功了,微信會推送一個XML格式的數據過來,JAVA請用下面的代碼解析出來
public static byte[] readBytes(InputStream in) throws IOException {  
        byte[] temp = new byte[in.available()];  
        byte[] result = new byte[0];  
        int size = 0;  
        while ((size = in.read(temp)) != -1) {  
            byte[] readBytes = new byte[size];  
            System.arraycopy(temp, 0, readBytes, 0, size);  
            result = SystemUtil.mergeArray(result,readBytes);  
        }  
        return result;  
    }  
 
        

②校驗簽名

微信支付傳過來數據,但未必是對的,所以把里面的簽名拿出來,把別的變量拿出用keyvalue同樣的方式加密再和簽名對比,一樣的就是對的。

③返回SUCCESS

④微信會在30分鍾內進行8次回調,這是擔心你網絡問題等拿不到支付后的數據,所以你要判斷這個東西是否已經成功處理過了

⑤處理:不外乎就是拿出訂單號等,寫入自己的數據庫里。

 
        
4、完成部分
 
        
wx.chooseWXPay({
    timestamp: 0, // 支付簽名時間戳,注意微信jssdk中的所有使用timestamp字段均為小寫。但最新版的支付后台生成簽名使用的timeStamp字段名需大寫其中的S字符
    nonceStr: '', // 支付簽名隨機串,不長於 32 位
    package: '', // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=***)
    signType: '', // 簽名方式,默認為'SHA1',使用新版支付需傳入'MD5'
    paySign: '', // 支付簽名
    success: function (res) {
        // 支付成功后的回調函數
    }
});
看到“支付成功后的回調函數”了嗎?就在這里面寫完成后跳轉的頁面,location.href=xxx,完結了~

 

大功告成……唉,真不好意思說大功,像支付寶一樣的話也就一天半天的事,這個卻整了那么久。

給官方的建議是,Demo能否出現在顯眼的位置,能否做一個針對DEMO的文檔或者說明(例如這個demo是適合哪個版本的都沒說),對DEMO做相應修改或者填寫各種key和id就行了,頂多再教一下配置些什么,畢竟很多東西都是死的,不需要用戶全部敲一遍,只不過按照規則填就是了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM