微信支付的那些坑!
開通和審核 微信支付和支付寶商家平台一樣,都是要審核資質的,支付寶個人認證可以使用擔保支付,雖然需要用戶確認收貨之后才能收到資金,但是好歹也是能用的。微信直接不讓個人使用支付。只有企業以上級別的服務號才能申請。 開通&認證 支付寶注冊企業賬號,進行企業認證,我總共就花了10分鍾,包括公司資質審核,打款到公賬確認公賬等步驟。效率高到簡直無法想象。 微信支付需要已經認證過的服務號才能開通支付。提交完資質,等待審核,花了5個工作日的時間才告訴我資質審核過了,對,沒錯,是5個工作日,中間隔了一個周末,微信稱2-7個工作日認證完成,還是實現諾言了。 開通支付 支付寶需要簽約服務,這里我簽約的是即時到帳的,花了2天時間。 微信開通認證之后,登陸商戶平台配置一下就可以開干了,這點從速度方面比支付寶強點,因為它把支付用途啥的都放到第一步的認證里面了,而支付寶是放在后面的簽約服務里面進行審核的。 這些步驟完成之后,就可以開始開發了。雖然如此,從整體進度上面,支付寶還是略勝微信一籌的。 開發 文檔&DEMO 微信的文檔,恩,在微信公眾平台有一份,在商戶平台又有另外一份,而且內容還不一樣。。。我主要需要在公眾號里面支付,所以選擇了微信的JSAPI。在公眾平台里面,關於JS支付的只有一小段。如下: signature 的值是用多個參數 sha1 加密的結果,詳細流程即: 1, 通過 appid +appsecert 獲取公眾號的 access_token(不是用戶的 access_token) 獲取到以上 5 步之后,將 jsapi_ticket,nonceStr, timestamp,URL 組成 Query String(GET 參數),即: $queryString ="jsapi_ticket=XXX&noncestr=XXX×tamp=XXX&url=XXX"; 生成 Query String 要注意: signature 的值就是 sha1 加密后的結果,即: $signature =sha1($queryString);
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的頁面地址為 那么你要把安全目錄設置為 這樣設置之后,如果你在如下地址調用,則會報錯 你可以設置多個支付目錄,如果需要的話。 2、設置回調地址,這個不解釋。 3、設置警告地址,不解釋。 4、商戶平台里面設置密鑰,在登錄了商戶平台之后,位於賬戶設置-API安全里面,先裝數字證書,然后設置密鑰,32位字符串。設置完了,自己記下來,沒錯,要自己記下來,因為沒法再查看了。 公眾號支付測試的時候測試鏈接要從公眾號里點進去才能出現支付界面,不然會一直報chooseWXPay fail ,這是個大坑啊
最終前端調用代碼如下:
|