1. 程式人生 > >微信支付的那些坑

微信支付的那些坑

前言

最近在研究微信支付,感覺在微信裡面買東西,直接微信支付還是蠻方便的,沒有支付寶那麼麻煩,刷刷朋友圈,順便就買點東西,生活是如此的愜意,心想微信的這個支付肯定可以做到很牛逼,因為“錢景”無限啊!於是,我開始了這個噩夢般的旅程。

開通和稽核

微信支付和支付寶商家平臺一樣,都是要稽核資質的,支付寶個人認證可以使用擔保支付,雖然需要使用者確認收貨之後才能收到資金,但是好歹也是能用的。微信直接不讓個人使用支付。只有企業以上級別的服務號才能申請。

開通&認證

支付寶註冊企業賬號,進行企業認證,我總共就花了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位字串。設定完了,自己記下來,沒錯,要自己記下來,因為沒法再查看了。