最近做小程序,涉及到微信支付,看了看微信小程序开发文档,尽管之前做过微信支付,还是有点懵逼,不过好在之前研究过,不然真的是无从下手。对比了一下发现,其实小程序中做支付比公众号支付要省事很多,因为不需要支付授权目录,也不需要授权域名,但是支付流程却比公众号多了一步,就是统一下单是预支付,然后需要对预支付的结果再次签名之后,才调起支付。
微信小程序中实现微信支付
前期准备:
1.开通了微信支付,并且小程序绑定了微信支付;
2.准备好小程序的appid,微信支付的商户号,支付秘钥。

商户系统和微信支付系统主要交互:
1、小程序内调用登录接口,获取到用户的openid
此步骤在小程序内完成,也很简单,方法见:【小程序登录API

2、调用商户服务器支付统一下单接口,进行预支付

[php] view plain copy
  1. /** 
  2.  * 预支付请求接口(POST) 
  3.  * @param string $openid    openid 
  4.  * @param string $body      商品简单描述 
  5.  * @param string $order_sn  订单编号 
  6.  * @param string $total_fee 金额 
  7.  * @return  json的数据 
  8.  */  
  9. public function prepay(){  
  10.     $config = $this->config;  
  11.       
  12.     $openid = I('post.openid');  
  13.     $body = I('post.body');  
  14.     $order_sn = I('post.order_sn');  
  15.     $total_fee = I('post.total_fee');  
  16.       
  17.     //统一下单参数构造  
  18.     $unifiedorder = array(  
  19.         'appid'         => $config['appid'],  
  20.         'mch_id'        => $config['pay_mchid'],  
  21.         'nonce_str'     => self::getNonceStr(),  
  22.         'body'          => $body,  
  23.         'out_trade_no'  => $order_sn,  
  24.         'total_fee'     => $total_fee * 100,  
  25.         'spbill_create_ip'  => get_client_ip(),  
  26.         'notify_url'    => 'https://'.$_SERVER['HTTP_HOST'].'/Api/Wxpay/notify',  
  27.         'trade_type'    => 'JSAPI',  
  28.         'openid'        => $openid  
  29.     );  
  30.     $unifiedorder['sign'] = self::makeSign($unifiedorder);  
  31.     //请求数据  
  32.     $xmldata = self::array2xml($unifiedorder);  
  33.     $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';  
  34.     $res = self::curl_post_ssl($url$xmldata);  
  35.     if(!$res){  
  36.         self::return_err("Can't connect the server");  
  37.     }  
  38.     // 这句file_put_contents是用来查看服务器返回的结果 测试完可以删除了  
  39.     //file_put_contents(APP_ROOT.'/Statics/log1.txt',$res,FILE_APPEND);  
  40.       
  41.     $content = self::xml2array($res);  
  42.     if(strval($content['result_code']) == 'FAIL'){  
  43.         self::return_err(strval($content['err_code_des']));  
  44.     }  
  45.     if(strval($content['return_code']) == 'FAIL'){  
  46.         self::return_err(strval($content['return_msg']));  
  47.     }  
  48.     self::return_data(array('data'=>$content));  
  49.     //$this->ajaxReturn($content);  
  50. }  
3、调用商户服务器再次签名接口,返回支付数据

[php] view plain copy
  1. /** 
  2.  * 进行支付接口(POST) 
  3.  * @param string $prepay_id 预支付ID(调用prepay()方法之后的返回数据中获取) 
  4.  * @return  json的数据 
  5.  */  
  6. public function pay(){  
  7.     $config = $this->config;  
  8.     $prepay_id = I('post.prepay_id');  
  9.       
  10.     $data = array(  
  11.         'appId'     => $config['appid'],  
  12.         'timeStamp' => time(),  
  13.         'nonceStr'  => self::getNonceStr(),  
  14.         'package'   => 'prepay_id='.$prepay_id,  
  15.         'signType'  => 'MD5'  
  16.     );  
  17.       
  18.     $data['paySign'] = self::makeSign($data);  
  19.       
  20.     $this->ajaxReturn($data);  
  21. }  
4、小程序内完成支付,商户服务器接收支付回调通知

小程序端代码:

[javascript] view plain copy
  1. wx.requestPayment({  
  2.    'timeStamp''',  
  3.    'nonceStr''',  
  4.    'package''',  
  5.    'signType''MD5',  
  6.    'paySign''',  
  7.    'success':function(res){  
  8.    },  
  9.    'fail':function(res){  
  10.    }  
  11. })  
服务器回调通知:

[php] view plain copy
  1. //微信支付回调验证  
  2. public function notify(){  
  3.     $xml = $GLOBALS['HTTP_RAW_POST_DATA'];  
  4.       
  5.     // 这句file_put_contents是用来查看服务器返回的XML数据 测试完可以删除了  
  6.     //file_put_contents(APP_ROOT.'/Statics/log2.txt',$res,FILE_APPEND);  
  7.       
  8.     //将服务器返回的XML数据转化为数组  
  9.     $data = self::xml2array($xml);  
  10.     // 保存微信服务器返回的签名sign  
  11.     $data_sign = $data['sign'];  
  12.     // sign不参与签名算法  
  13.     unset($data['sign']);  
  14.     $sign = self::makeSign($data);  
  15.       
  16.     // 判断签名是否正确  判断支付状态  
  17.     if ( ($sign===$data_sign) && ($data['return_code']=='SUCCESS') && ($data['result_code']=='SUCCESS') ) {  
  18.         $result = $data;  
  19.         //获取服务器返回的数据  
  20.         $order_sn = $data['out_trade_no'];          //订单单号  
  21.         $openid = $data['openid'];                  //付款人openID  
  22.         $total_fee = $data['total_fee'];            //付款金额  
  23.         $transaction_id = $data['transaction_id'];  //微信支付流水号  
  24.           
  25.         //更新数据库  
  26.         $this->updateDB($order_sn,$openid,$total_fee,$transaction_id);  
  27.           
  28.     }else{  
  29.         $result = false;  
  30.     }  
  31.     // 返回状态给微信服务器  
  32.     if ($result) {  
  33.         $str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';  
  34.     }else{  
  35.         $str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';  
  36.     }  
  37.     echo $str;  
  38.     return $result;  
  39. }  
我将完整的接口代码封装成了一个类文件,可以直接引入项目更改一下配置参数就可以使用的,源码下载:http://download.csdn.net/detail/sinat_35861727/9879682
小程序端完整代码如下:

[javascript] view plain copy
  1. /** 
  2.  * 支付函数 
  3.  * @param  {[type]} _payInfo [description] 
  4.  * @return {[type]}          [description] 
  5.  */  
  6. pay:function(_payInfo,success,fail){  
  7.     var payInfo = {  
  8.         body:'',  
  9.         total_fee:0,  
  10.         order_sn:''  
  11.     }  
  12.     Object.assign(payInfo, _payInfo);  
  13.     if(payInfo.body.length==0){  
  14.         wx.showToast({  
  15.             title:'支付信息描述错误'  
  16.         })  
  17.         return false;  
  18.     }  
  19.     if(payInfo.total_fee==0){  
  20.         wx.showToast({  
  21.             title:'支付金额不能0'  
  22.         })  
  23.         return false;   
  24.     }  
  25.     if(payInfo.order_sn.length==0){  
  26.         wx.showToast({  
  27.             title:'订单号不能为空'  
  28.         })  
  29.         return false;   
  30.     }  
  31.     var This = this;  
  32.     This.getOpenid(function(openid){  
  33.         payInfo.openid=openid;  
  34.         This.request({  
  35.             url:'api/pay/prepay',  
  36.             data:payInfo,  
  37.             success:function(res){  
  38.                 var data = res.data;  
  39.                 console.log(data);  
  40.                 if(!data.status){  
  41.                     wx.showToast({  
  42.                         title:data['errmsg']  
  43.                     })  
  44.                     return false;  
  45.                 }  
  46.                 This.request({  
  47.                     url:'api/pay/pay',  
  48.                     data:{prepay_id:data.data.data.prepay_id},  
  49.                     success:function(_payResult){  
  50.                         var payResult = _payResult.data;  
  51.                         console.log(payResult);  
  52.                         wx.requestPayment({  
  53.                             'timeStamp': payResult.timeStamp.toString(),  
  54.                             'nonceStr': payResult.nonceStr,  
  55.                             'package': payResult.package,  
  56.                             'signType': payResult.signType,  
  57.                             'paySign': payResult.paySign,  
  58.                             'success'function (succ) {  
  59.                                 success&&success(succ);  
  60.                             },  
  61.                             'fail'function (err) {  
  62.                                 fail&&fail(err);  
  63.                             },  
  64.                             'complete'function (comp) {   
  65.   
  66.                             }  
  67.                         })   
  68.                     }  
  69.                 })  
  70.             }  
  71.         })  
  72.     })  
  73. }  

相关文章: