微信支付的那些坑
前言
最近在研究微信支付,感覺在微信裡面買東西,直接微信支付還是蠻方便的,沒有支付寶那麼麻煩,刷刷朋友圈,順便就買點東西,生活是如此的愜意,心想微信的這個支付肯定可以做到很牛逼,因為“錢景”無限啊!於是,我開始了這個噩夢般的旅程。
開通和稽核
微信支付和支付寶商家平臺一樣,都是要稽核資質的,支付寶個人認證可以使用擔保支付,雖然需要使用者確認收貨之後才能收到資金,但是好歹也是能用的。微信直接不讓個人使用支付。只有企業以上級別的服務號才能申請。
開通&認證
支付寶註冊企業賬號,進行企業認證,我總共就花了10分鐘,包括公司資質稽核,打款到公賬確認公賬等步驟。效率高到簡直無法想象。 微信支付需要已經認證過的服務號才能開通支付。提交完資質,等待稽核,花了5個工作日的時間才告訴我資質稽核過了,對,沒錯,是5個工作日,中間隔了一個週末,微信稱2-7個工作日認證完成,還是實現諾言了。
開通支付
支付寶需要簽約服務,這裡我簽約的是即時到帳的,花了2天時間。 微信開通認證之後,登陸商戶平臺配置一下就可以開幹了,這點從速度方面比支付寶強點,因為它把支付用途啥的都放到第一步的認證裡面了,而支付寶是放在後面的簽約服務裡面進行稽核的。
這些步驟完成之後,就可以開始開發了。雖然如此,從整體進度上面,支付寶還是略勝微信一籌的。
開發
根據文件接入支付寶和微信的支付平臺
文件&DEMO
支付寶我就沒看文件,因為之前有做過,已經大體瞭解了。直接下了個DEMO改改就完成了。 微信的文件,恩,在微信公眾平臺有一份,在商戶平臺又有另外一份,而且內容還不一樣。。。 我主要需要在公眾號裡面支付,所以選擇了微信的JSAPI。在公眾平臺裡面,關於JS支付的只有一小段。如下:
wx.chooseWXPay({ timestamp: 0, // 支付簽名時間戳,注意微信jssdk中的所有使用timestamp欄位均為小寫。但最新版的支付後臺生成簽名使用的timeStamp欄位名需大寫其中的S字元 nonceStr: '', // 支付簽名隨機串,不長於 32 位 package: '', // 統一支付介面返回的prepay_id引數值,提交格式如:prepay_id=***) signType: '', // 簽名方式,預設為'SHA1',使用新版支付需傳入'MD5' paySign: '', // 支付簽名 success: function (res) { // 支付成功後的回撥函式 } }); 備註:prepay_id 通過微信支付統一下單介面拿到,paySign 採用統一的微信支付 Sign 簽名生成方法,注意這裡 appId 也要參與簽名,appId 與 config 中傳入的 appId 一致,即最後參與簽名的引數有appId, timeStamp, nonceStr, package, signType。 微信支付統一下單介面文件:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=9_1 微信支付簽名演算法:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3 微信支付開發教程:https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course3_tmpl&lang=zh_CN
看完方法,有點暈,在看完下面給出的三個連結裡面的內容,更暈了。然後又在商戶平臺找到一份文件。
這裡給了比較詳細的資料,也給出了js示例:
注:JS API的返回結果get_brand_wcpay_request:ok僅在使用者成功完成支付時返回。由於前端互動複雜,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以統一處理為使用者遇到錯誤或者主動放棄,不必細化區分。
示例程式碼如下:
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();
}
恩,於是我結合了文件和找到的demo,結合這一段內容開始測試,結果發現,完全沒反應。是的,在我的iPhone上面是沒有反應的,也許哪裡出了問題,一直搞不出反應。 然後我想到了前面還有一種chooseWXPay
,搜尋了一下,這是新版介面的方法。結合下面的文件引數的計算,成功了。結果是這樣的
wx.chooseWXPay({
appId: '{{ $jsParameters['appId'] }}',
timestamp: '{{ $jsParameters['timeStamp'] }}', // 支付簽名時間戳,注意微信jssdk中的所有使用timestamp欄位均為小寫。但最新版的支付後臺生成簽名使用的timeStamp欄位名需大寫其中的S字元
nonceStr: '{{ $jsParameters['nonceStr'] }}', // 支付簽名隨機串,不長於 32 位
package: '{{ $jsParameters['package'] }}', // 統一支付介面返回的prepay_id引數值,提交格式如:prepay_id=***)
signType: '{{ $jsParameters['signType'] }}', // 簽名方式,預設為'SHA1',使用新版支付需傳入'MD5'
paySign: '{{ $jsParameters['paySign'] }}', // 支付簽名
success: function (res) {
if(res.errMsg == "chooseWXPay:ok" ) {
//支付成功
}else{
alert(res.errMsg);
}
},
cancel:function(res){
//支付取消
}
});
這裡的$jsParameters
是在後臺使用微信支付的DEMO裡面提供的class生成的。
include_once("WxPayPubHelper.php");
...
public function getParameters(Order $order)
{
$jsApi = new JsApi_pub();
$unifiedOrder = new UnifiedOrder_pub();
//$unifiedOrder->setParameter("detail", $this->order->product->brief_desc);//商品描述
$unifiedOrder->setParameter("body", $order->product->name);//商品描述
$unifiedOrder->setParameter("out_trade_no", $order->order_number);//商戶訂單號
$unifiedOrder->setParameter("total_fee", $order->price * 100);//總金額,騰訊預設支付金額單位為【分】
$unifiedOrder->setParameter("notify_url", WxPayConf_pub::NOTIFY_URL);//通知地址
$unifiedOrder->setParameter("trade_type", "JSAPI");//交易型別
//非必填引數,商戶可根據實際情況選填
$unifiedOrder->setParameter("openid", Auth::user()->wx_openid);//商品ID
$unifiedOrder->setParameter("product_id", $order->product->id);//商品ID
$prepay_id = $unifiedOrder->getPrepayId();
$jsApi->setPrepayId($prepay_id);
return $jsApi->getParameters();
}
我描述你一臉啊,明顯第一個是使用者openid
還有這個
支付簽名時間戳,注意微信jssdk中的所有使用timestamp欄位均為小寫。但最新版的支付後臺生成簽名使用的timeStamp欄位名需大寫其中的S字元
你很難搞清楚啥時候改用大寫,啥時候該用小寫。
還有這個
備註:prepay_id 通過微信支付統一下單介面拿到,paySign 採用統一的微信支付 Sign 簽名生成方法,注意這裡 appId 也要參與簽名,appId 與 config 中傳入的 appId 一致,即最後參與簽名的引數有appId, timeStamp, nonceStr, package, signType。
就是在呼叫chooseWXPay
的時候,你要自己加上appId,注意,I是大寫。否則採用JSAPI方式的時候會提示出錯。
還有這個
注:JS API的返回結果get_brand_wcpay_request:ok僅在使用者成功完成支付時返回。由於前端互動複雜,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以統一處理為使用者遇到錯誤或者主動放棄,不必細化區分。
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {} // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在使用者支付成功後返回 ok,但並不保證它絕對可靠。
}
老版的接口裡面是這樣描述返回結果的。但是在新版裡面變了,是變了,但是滿世界找不到變成啥樣了。只能自己打出來測試,結果變成如下
success: function (res) {
if(res.errMsg == "chooseWXPay:ok" ) {
//支付成功
...
新版接口裡面取消是沒有反應的,因為只有success回撥。沒有任何一個地方說了如何監聽使用者取消支付。只能自己猜,結果,我果然猜對了。
success: function (res) {
if(res.errMsg == "chooseWXPay:ok" ) {
//支付成功
}else{
alert(res.errMsg);
}
},
cancel:function(res){
//支付取消
}
你以為是res.errMsg == "chooseWXPay:cancel"
嗎?騷年,你還是太年輕。
設定坑
1、要設定好安全支付目錄。這個啥意思?
1、所有使用JS API方式發起支付請求的連結地址,都必須在支付授權目錄之下;
2、最多設定3個支付授權目錄, 且域名必須通過ICP備案;
3、頭部要包含http或https,須細化到二級或三級目錄,以左斜槓“/”結尾。
修改會影響線上交易,距正式生效有十分鐘左右延遲,建議你避開交易高峰時間修改
就是說,你將要呼叫JSAPI的那個頁面的連結要在這個目錄之下才可以。否則,會彈出提示說你的目錄沒許可權。比如你呼叫JSAPI的頁面地址為
http://www.xx.oo/pay/order/1
那麼你要把安全目錄設定為
http://www.xx.oo/pay/order/
這樣設定之後,如果你在如下地址呼叫,則會報錯
http://www.xx.oo/pay/newOrder/1
你可以設定多個支付目錄,如果需要的話。
2、設定回撥地址,這個不解釋。
3、設定警告地址,不解釋。
4、商戶平臺裡面設定金鑰,在登入了商戶平臺之後,位於賬戶設定
-API安全
裡面,先裝數字證書,然後設定金鑰,32位字串。設定完了,自己記下來,沒錯,要自己記下來,因為沒法再查看了。