微信支付的那些坑!!!
微信支付的那些坑!
开通和审核 微信支付和支付宝商家平台一样,都是要审核资质的,支付宝个人认证可以使用担保支付,虽然需要用户确认收货之后才能收到资金,但是好歹也是能用的。微信直接不让个人使用支付。只有企业以上级别的服务号才能申请。 开通&认证 支付宝注册企业账号,进行企业认证,我总共就花了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 ,这是个大坑啊
最终前端调用代码如下:
|