一次痛苦又甜蜜的微信支付踩坑之旅

凡是和錢打交道的事,沒有同樣是容易的。這是我第一次接觸微信支付,發現網上仍是有不少同窗在求助,XXX了怎麼辦?XXX是什麼狀況?爲了幫助更多的小夥伴脫離「苦海」,我決定寫下此次的踩坑之旅,給更多的人幫助。

介紹php

微信支付方式分爲刷卡支付、公衆號支付、掃碼支付、APP支付、H5支付、小程序支付。html

先從應用場景來各自說一說,這樣,可以最快的判斷出應該選擇哪種支付。ios

  • 刷卡支付:使用掃描設備(掃描槍)多見於超市、便利店使用
  • 公衆號支付:嵌入公衆號的H5頁面
  • 掃碼支付:用戶打開「微信掃一掃」,掃描商戶的二維碼並支付
  • APP支付:外部APP應用,用戶觸發支付時,轉到微信內完成支付
  • H5支付:非微信內置瀏覽器請求微信支付
  • 小程序支付:用戶在微信小程序中使用微信支付

背景nginx

咱們公司申請的是微信服務號,須要微信支付的是嵌入服務號內部的網頁,因此根據介紹,應該選擇「公衆號支付」。web

開發步驟express

首先不要被微信支付的開發嚇着,其實它很簡單。先仔細看公衆號支付的文檔,看不懂的多看幾遍,還看不懂的,動手操做一下,試一試。json

文檔在此:
pay.weixin.qq.com/wiki/doc/ap…axios

  • 步驟一:統一下單

跟着文檔,咱一點點來,搞明白每一步是爲何,就不會迷迷糊糊搞不清楚了。小程序

首先說一下,這個接口是後臺須要完成的,這個接口的目的就是獲取prepay_id,它是預支付交易回話標識。將prepay_id傳給前臺,前臺調用js-sdk,這屬於步驟二的範圍了,一會講。微信小程序

接口連接
URL地址:api.mch.weixin.qq.com/pay/unified…

在文檔中說明了,必須使用post 方法請求微信給的接口連接,傳入的數據也必須是xml格式,返回的也是xml的。醉了?不要醉,微信是這樣的,支付寶也是這樣的。手動微笑,接受吧。

接着來。

簡單粗暴貼代碼:

// '/addOrder'是留給前臺的調用接口
router.post('/addOrder',(req,res)=>{    
const addOrderUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder';    
var client_ip = "";    
client_ip = req.body.ipaddr;    
var appid = "1234567890"; // 服務號|公衆號的appid    
var body = "商品簡單描述-測試"; // 商品簡單描述    
var mch_id= "1234567890"; // 商戶號,申請微信支付,騰訊給的商戶號    
// var device_info = "WEB";  
var nonce_str = getRanId(32); // 隨機字符串 
var out_trade_no = "" +new Date().getTime() + Math.floor( Math.random() * 10 ); //商戶訂單號
var total_fee = req.body.total_fee; //支付金額,單位:分    
var sign = "";    
var notify_url = "http://123.456.789"; //異步接收微信支付結果通知的回調地址    
var trade_type = "JSAPI"; // 交易類型    
var openid = req.session.openId;    
console.log(openid);    
var stringA = `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=${client_ip}&total_fee=${total_fee}&trade_type=${trade_type}`;    
var stringSighTemp = stringA+"&key=****#####jiaoyuguihuayuan----***"; //32位的商戶key,自定義的,這裏爲了隱私,我用的特殊符號給大家展現   
sign = md5(stringSighTemp).toUpperCase();    
var xml = `<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>${client_ip}</spbill_create_ip>     
<total_fee>${total_fee}</total_fee>  
<trade_type>${trade_type}</trade_type>    
<sign>${sign}</sign>    
</xml>`;
var Res = res;axios({  
    method: 'post',   
    url: addOrderUrl,   
    data: xml,   
    responseType: 'text/xml',   
    headers: {     
       'Content-Type': 'text/xml' 
    }
 }).then( res=>{   
    console.log(res)  
    Res.send(res.data)
 }).catch( err=>{   
    console.log( err)})
})複製代碼

說明

client_ip 參數 是客戶端的ip地址,原本我是在後臺獲取客戶端ip地址的,由於咱們使用了nginx代理,req.ip 返回的都是 ::ffff:127.0.0.1 這是IPV6格式的字符串。網上有一個答案對此作出瞭解釋: stackoverflow.com/questions/2…

在這裏,我用的一個網上的腳本在前臺獲取的, http://pv.sohu.com/cityjson?ie=utf-8
使用方法: window.ipaddr = returnCitySN[‘cip’];
其餘的參數,都是參考微信支付的要求去寫的。

出現的錯誤

XML格式錯誤

而查看文檔,緣由是這樣的


我:#&(%#@+%),也不給個詳細點的說明…

這種錯誤須要「頓悟」,我忽然發現了個人錯誤。是我理解錯了!我給body標籤加了一個 <![CDATA[]]> 致使個人xml格式錯誤,實際上是有detail字段才須要添加 <[CDATA[]]>, 其餘的不須要。

我:咳咳,低級錯誤。注意看文檔,按照要求來,既很少添什麼,也不要少什麼。

我把<[CDATA[]]>去掉以後,發現果然是這個緣由,再也不出現XML格式錯誤了,然而,仍是高興的太早,由於它報了簽名錯誤。呵呵呵~

簽名錯誤


文檔中說的簽名計算很嚴格:
第一步,設全部發送或者接收到的數據爲集合M,將集合M內非空參數值的參數按照參數名ASCII碼從小到大排序(字典序),使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

特別注意如下重要規則:
第一步,設全部發送或者接收到的數據爲集合M,將集合M內非空參數值的參數按照參數名ASCII碼從小到大排序(字典序),使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

◆ 參數名ASCII碼從小到大排序(字典序);
◆ 若是參數的值爲空不參與簽名;
◆ 參數名區分大小寫; (公衆號支付全是小寫)
◆ 驗證調用返回或微信主動通知簽名時,傳送的sign參數不參與簽名,將生成的簽名與該sign值做校驗。
◆ 微信接口可能增長字段,驗證簽名時必須支持增長的擴展字段

第二步,在stringA最後拼接上key獲得stringSignTemp字符串,並對stringSignTemp進行MD5運算,再將獲得的字符串全部字符轉換爲大寫,獲得sign值signValue。

◆ key設置路徑:微信商戶平臺(pay.weixin.qq.com)–>帳戶設置–>API安全–>密鑰設置

這裏我查閱了一些資料,看到過有這樣幾種錯誤狀況:
key 看錯了,這裏應該寫商戶的key,而這個key 是用戶手動設置的,長32位。注意:本身保存一份,由於設置好了以後是無法打開查看的。


還有一種錯誤,我以爲很離譜啊,body裏面不能有中文,然而,我把body中的文字改成英文,發現並不能改變現狀,其實用中文是能夠的。

總之,找到的這些錯誤,統統對個人狀況沒用!

而後這又須要「頓悟」,原來stringA字符串我用了換行符把很長的字符隔開,這致使換行符被轉換爲Ascall碼中的 \n 寫進了簽名裏面,因此,sign錯誤,因此要麼,把換行符統統去掉,要麼用「」鏈接,捨棄。我把換行都去掉以後,就沒有簽名錯誤了。

噹噹噹當 ~


終於完成了第一步,後臺成功的返回了咱們須要的prepay_id

這裏爲了安全,對於返回sign,和發送的sign進行對比,徹底相等以後,才能把結果返回給前臺。

  • 步驟二:調用微信js-sdk接口

微信支付

發起一個微信支付請求

前臺收到的是xml數據,要先解析一下,獲得prepay_id

而後調用微信支付js-sdk,爲了你們少走一些彎路,我先來正確的寫法,關鍵步驟以下:

var {prepay_id,appid} = getInfo(res.data); //從後臺數據中獲取appid 和 prepay_id
nonceStr = getRanId(32);
timeStamp = new Date().getTime();
var stringA = "appId="+appid+"&nonceStr="+nonceStr+"&package=prepay_id="+prepay_id+"&signType=MD5&timeStamp="+timeStamp;
var stringSignTemp = stringA+"&key=****#####jiaoyuguihuayuan----***";
paySign = md5(stringSignTemp).toUpperCase();
window.wx.chooseWXPay({    
timestamp: timeStamp, // 支付簽名時間戳,注意微信jssdk中的全部使用timestamp字段均爲小寫。但最新版的支付後臺生成簽名使用的timeStamp字段名需大寫其中的S字符    
nonceStr: nonceStr, // 支付簽名隨機串,不長於 32 位    
package: "prepay_id=" + prepay_id, // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=\*\*\*)    
signType: 'MD5', // 簽名方式,默認爲'SHA1',使用新版支付需傳入'MD5'    
paySign: paySign, // 支付簽名 
success: function (res) {        
// 支付成功後的回調函數        
    console.log(res)   
 },   
fail: function(err){     
    console.log(err)  
}});複製代碼

備註:prepay_id 經過微信支付統一下單接口拿到,paySign 採用統一的微信支付 Sign 簽名生成方法,注意這裏 appId 也要參與簽名,appId 與 config 中傳入的 appId 一致,即最後參與簽名的參數有appId, timeStamp, nonceStr, package, signType。

注意,我要講個坑點~

調用js-sdk時,簽名中的字段都是小駝峯的寫法,timeStamp是這樣寫的,可是wx.config中,timestamp 是全小寫的,因此,親們,千萬不要搞錯了,我在這裏就被坑了好一會呢。

寫完簽名以後,當你用微信web開發者工具去測試的話,就會看到,「不支持模擬」這樣的提示。這個時候,不要猶豫,直接上真機去測試,這並非咱們的程序出現了問題。

小tips: 在真機上,咱們是沒有辦法看到console出的一些調試信息,因此,要想個辦法,能夠用alert,也能夠把調試信息打印在屏幕上面,我選擇打印在屏幕上。這裏要說一些,微信給的文檔沒有那麼齊全,有一些是要試試才指導的,好比wx.config中的success和fail函數,參數信息怎麼打印,實際上是res.errMsg和err.errMsg.

上面我說的這些你都注意到了,可是微信支付的控件你依然調動不起來的話,多是微信商戶平臺的開發配置出現了問題,在 產品中心-開發配置-支付配置-公衆號支付 中進行配置,配置的時候,注意必定要到最後一級目錄,好比我要在cms.123.456/book/list/index.html頁面中去進行微信支付,那麼你的配置應該是 cms.123.456/book/list/

好了,開發中基本上全部的坑都提到了,這是創建在你配置沒有出錯的狀況下。接下來,看看到底能不能真的支付。

完成



大功告成,讓我想起了,最近流行的一句話,你這磨人的小妖精,微信支付!

但願能給大家帶來幫助~

做者:justsso 連接:https://juejin.cn/post/1 來源:掘金 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

相關文章
相關標籤/搜索