这几天在做小程序的支付,没有用官方的SDK,这里就纯用官方的文档搞一发。

* 注作者使用的PHP,不过支付流程都是这样

开发前必读

主要流程

  • 小程序前端发送求参请求
  • 接受请求封装 “统一下单” 获取package
  • 小程序接受 “统一下单” 获取的package值带入wx.requestPayment发起支付请求

准备工具

  • 申请小程序微信支付
  • 拿到小程序微信支付的商户号及设置秘钥

注意:小程序就只需要这两步,如果是web的话还需要设置支付目录授权域名,文档里面也有写的:https://pay.weixin.qq.com/wik...


统一下单

官方文档:https://pay.weixin.qq.com/wik...

  1. /**
  2. * 统一订单
  3. */
  4. public function unifiedorder(){
  5. // 以下配置是必填项,如有其它需求请自行配置
  6. $config = array(
  7. 'appid' => 'xxxxxxx',//这里是小程序appid
  8. 'mch_id' => 'xxxxxxx',//商户ID
  9. 'nonce_str' => $this->getNonceStr(),//随机字符串
  10. 'body' => '这里是测试 - 测试',//请按照文档要求填写合格名称
  11. 'out_trade_no' => time().$this->getNonceStr(2),//流水单号
  12. 'total_fee' => '20',//金额,分为单位,这里是0.2元
  13. 'spbill_create_ip' => '123.123.123.123',//当前IP
  14. 'notify_url' => 'http://xxxx.com',//请恕我愚昧,我没搞懂他有什么用
  15. 'trade_type' => 'JSAPI',//必须填写JSAPI
  16. 'openid' => 'xxxxxxxx'//当前用户的openid,在trade_type=JSAPI的时候,此项就变成必填项了
  17. );
  18. $config['sign'] = $this->getSignPay($config);
  19. $xmlData = $this->ToXml($config);//转成xml数据
  20. $postData = $this->http_post($xmlData);
  21. $arrayData = $this->FromXml($postData);
  22. if($arrayData['return_code'] == 'SUCCESS' || $arrayData['result_code'] == 'SUCCESS'){
  23. return $arrayData['prepay_id'];//重点来了:走了这么多路,就为了这个值。到这一步就证明成功一多半了。
  24. }else{
  25. return $arrayData;//返回错误
  26. }
  27. }
  28. /**
  29. * 获取签名
  30. */
  31. public function getSignPay($config){
  32. $key = 'xxxxxxx';//商户秘钥,就是自己生成的32位密码
  33. $strA = 'appid='.$config['appid'].'&body='.$config['body'].'&mch_id='.$config['mch_id'].'&nonce_str='.$config['nonce_str'].'&notify_url='.$config['notify_url'].'&spbill_create_ip'.$config['spbill_create_ip'].'&total_fee='.$config['total_fee'].'&trade_type='.$config['trade_type'];//ASCII 字典序
  34. $strB = $strA.'&key='.$key;
  35. $sign = strtoupper(md5($strB));//大写MD5
  36. return $sign;
  37. }
  38. /**
  39. * 随机字符串 32位
  40. */
  41. public function getNonceStr($length = 32){
  42. $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
  43. $str ="";
  44. for ( $i = 0; $i < $length; $i++ ) {
  45. $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
  46. }
  47. return $str;
  48. }
  49. /**
  50. * array转XML
  51. */
  52. public function ToXml($data){
  53. if(!is_array($data) || count($data) <= 0){
  54. throw new WxPayException("数组数据异常!");
  55. }
  56. $xml = "<xml>";
  57. foreach ($data as $key=>$val){
  58. $xml.="<".$key.">".$val."</".$key.">";
  59. }
  60. $xml.="</xml>";
  61. return $xml;
  62. }
  63. /**
  64. * xml转array
  65. */
  66. public function FromXml($xml){
  67. if(!$xml){
  68. throw new WxPayException("xml数据异常!");
  69. }
  70. libxml_disable_entity_loader(true);
  71. $this->values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
  72. return $this->values;
  73. }
  74. /**
  75. * post 请求
  76. */
  77. public function http_post($url,$param,$post_file=false){
  78. $oCurl = curl_init();
  79. if(stripos($url,"https://")!==FALSE){
  80. curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
  81. curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
  82. curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
  83. }
  84. if (PHP_VERSION_ID >= 50500 && class_exists('\CURLFile')) {
  85. $is_curlFile = true;
  86. } else {
  87. $is_curlFile = false;
  88. if (defined('CURLOPT_SAFE_UPLOAD')) {
  89. curl_setopt($oCurl, CURLOPT_SAFE_UPLOAD, false);
  90. }
  91. }
  92. if (is_string($param)) {
  93. $strPOST = $param;
  94. }elseif($post_file) {
  95. if($is_curlFile) {
  96. foreach ($param as $key => $val) {
  97. if (substr($val, 0, 1) == '@') {
  98. }
  99. }
  100. }
  101. $strPOST = $param;
  102. } else {
  103. $aPOST = array();
  104. foreach($param as $key=>$val){
  105. $aPOST[] = $key."=".urlencode($val);
  106. }
  107. $strPOST = join("&", $aPOST);
  108. }
  109. curl_setopt($oCurl, CURLOPT_URL, $url);
  110. curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );
  111. curl_setopt($oCurl, CURLOPT_POST,true);
  112. curl_setopt($oCurl, CURLOPT_POSTFIELDS,$strPOST);
  113. $sContent = curl_exec($oCurl);
  114. $aStatus = curl_getinfo($oCurl);
  115. curl_close($oCurl);
  116. if(intval($aStatus["http_code"])==200){
  117. return $sContent;
  118. }else{
  119. return false;
  120. }
  121. }

好了现在已经获取到了 prepay_id 的值,我们的统一下单就算完成了,其实我更乐意叫他数据封装


小程序微信支付

官方文档:https://developers.weixin.qq....

先来一个插曲,首先我们小程序的前端需要去触发pay,实现的功能肯定是要点击小程序的一个触发,然后才能支付对吧,


  1. pay:function(e){
  2. //这里面使用post去请求。然后通过我接下来要写的API支付代码获取小程序支付参数
  3. success:function(res){
  4. wx.requestPayment({
  5. 'timeStamp':toString(res.timeStamp),//这里转字符串,这里被坑过,不转的话可能会出现total_fee为空
  6. 'nonceStr':toString(res.nonceStr),
  7. 'package':toString(res.package),
  8. 'signType':'MD5',
  9. 'paySign':toString(res.paySign),
  10. success:function(res){
  11. console.log(res);//这里可以跳转到带参地址
  12. },
  13. fail:function(res){
  14. console.info('支付失败',res);
  15. },
  16. complete:function(){
  17. console.info('支付触发回调',res);
  18. }
  19. })
  20. }
  21. }

api支付

也就是上面小程序代码的后端请求地址


  1. /**
  2. * api组装数据
  3. */
  4. public function payApiBlack(){
  5. $appid = 'xxxxxx';//小程序appid,上面有重复,不过这样比较直观
  6. $timeStamp = time();
  7. $nonceStr = $this->getNonceStr();//这是调用统一下单里面的方法,为了直观,我把这些代码都写在了一个类里
  8. $package = 'prepay_id='.$this->unifiedorder();
  9. $signType = 'MD5';
  10. $key = 'xxxxxx';//这里是商户秘钥,32位,同上面也有
  11. $strA = 'appId='.$appid.'&nonceStr='.$nonceStr.'package='.$package.'&= signType='.$signType.'&timeStamp='.$timeStamp.'&key='.$key;
  12. $paySign = strtoupper(md5($strA));
  13. $data = array(
  14. 'appid'=>$appid,
  15. 'timeStamp'=>$timeStamp,
  16. 'nonceStr'=>$nonceStr,
  17. 'package'=>$package,
  18. 'signType'=>$signType
  19. );
  20. return $data;//返回给小程序
  21. }

以上就是全部代码,还有小程序的支付回调没有什么信息,所以,我的思路判断success后进行跳转带参


  1. //此代码为wx.requestPayment success,部分代码省略
  2. //res 回调参数包括用户uid及其他重要传递
  3. success:function(res){
  4. wx.redirect({
  5. url:'pages/pay/done?uid='+res.uid
  6. })
  7. }

当然那个统一下单的 notify_url 好像与回调有关,至于怎么用,试了几次回调的CURD都没反应,所以有空再研究啦。

以上代码仅作为支付流程解释,所以真正要用到项目上,还是去套官方的SDK吧,毕竟涉及到钱嘛

原文地址:https://segmentfault.com/a/1190000015867859

微信小程序支付全问题解决的更多相关文章

  1. .Net后台实现微信小程序支付

    最近一直再研究微信支付和支付宝支付,官方支付文档中一直在讲与第三方支付打交道的原理,却没有介绍我们自己项目中的APP与后台该怎么交互(哈哈,人家也没必要介绍这一块).拜读了官方文档和前辈们的佳作,自己 ...

  2. 微信小程序支付步骤

    http://blog.csdn.net/wangsf789/article/details/53419781 最近开发微信小程序进入到支付阶段,一直以来从事App开发,所以支付流程还是熟记于心的.但 ...

  3. 微信小程序支付及退款流程详解

    微信小程序的支付和退款流程 近期在做微信小程序时,涉及到了小程序的支付和退款流程,所以也大概的将这方面的东西看了一个遍,就在这篇博客里总结一下. 首先说明一下,微信小程序支付的主要逻辑集中在后端,前端 ...

  4. Java 后端微信小程序支付demo (网上说的坑里面基本上都有)

    Java 后端微信小程序支付 一.遇到的问题 1. 商户号该产品权限未开通,请前往商户平台>产品中心检查后重试 2.签名错误 3.已经调起微信统一下单接口,可以拿到预支付ID,但是前端支付的时候 ...

  5. php对接微信小程序支付

    前言:这里我就假装你已经注册了微信小程序,并且基本的配置都已经好了.注: 个人注册小程序不支持微信支付,所以我还是假装你是企业或者个体工商户的微信小程序,其他的商户号注册,二者绑定,授权,支付开通,就 ...

  6. 微信小程序支付遇到的坑

    1,微信公众号支付和微信小程序支付有差异 微信公众号:可以直接跳转走h5的微信支付 微信小程序:在测试环境.沙箱环境使用微信公众号的跳转支付没有问题,在线上存在支付异常 最后商讨的解决方法 openi ...

  7. 微信小程序支付接入注意点

    一.微信支付后台服务器部署 服务器采用ubuntu16.04 + php7.0 + apache2.0. 微信支付后台服务使用了curl 和 samplexml ,因此php.ini配置中必须开启这两 ...

  8. 微信小程序支付开发之申请退款

    微信小程序支付跟微信公众号支付类似,这里不另做记录,如果没有开发过支付,可以查看我关于微信支付的文章 重点记录微信小程序申请退款开发过程中遇到一些坑. 退款接口比支付接口接口多了一个 双向证书 证书介 ...

  9. 微信小程序支付接入实战

    1. 微信小程序支付接入实战 1.1. 需求   最近接到一个小程序微信支付的需求,需要我写后台支持,本着能不自己写就不自己写的cv原则,在网上找到了些第三方程序,经过尝试后,最后决定了这不要脸作者的 ...

随机推荐

  1. java获取本周 上周的所有日期

    1 根据当前日期获得所在周的日期区间(周一和周日日期) public String getTimeInterval(Date date) { Calendar cal = Calendar.getIn ...

  2. Ado.net设计模式

    连接类 连接类有固定的使用模式,这是常用的乐观模式: using (var conn = new SqlConnection(connstr)) { conn.Open(); //执行各种数据库操作 ...

  3. AIZU AOJ 2309 Vector Compression 最小树形图(朱—刘算法)

    题意简述:给定若干个相同维度的向量,寻找一种排序方法,使得所有向量的表示长度总和最低. 所谓表示长度为(Aj-r*Ai)^2,其中i<j  数据范围:向量总数和维度均小于100 思路:(1)首先 ...

  4. div标签的闭合检查

    什么叫DIV标签有没有闭合呢?有<div>开头就应该有</div>来结尾闭合了.有时候写代码写 了<div>,忘记</div>结尾,谓之没有闭合也. 如 ...

  5. Ueditor 单独使用上传图片及上传附件方法

    1 <script type="text/plain" id="upload_ue"></script> 2 <script ty ...

  6. unable to unroll loop 报错

    unable to unroll loop, loop does not appear to terminate in a timely manner (1024 iterations) 原本代码 f ...

  7. bzoj 1650: [Usaco2006 Dec]River Hopscotch 跳石子【贪心+二分】

    脑子一抽写了个堆,发现不对才想起来最值用二分 然后判断的时候贪心的把不合mid的区间打通,看打通次数是否小于等于m即可 #include<iostream> #include<cst ...

  8. MySQL性能优化神器Explain

    本文涉及:MySQL性能优化神器Explain的使用 简介 虽然使用Explain不能够马上调优我们的SQL,它也不能给予我们一些调整建议,但是它能够让我们了解MySQL 优化器是如何执行SQL 语句 ...

  9. [Code+#1]大吉大利,晚上吃鸡!

    输入输出样例 输入样例#1: 7 7 1 7 1 2 2 2 4 2 4 6 2 6 7 2 1 3 2 3 5 4 5 7 2 输出样例#1: 6 输入样例#2: 5 5 1 4 1 2 1 1 3 ...

  10. Elasticsearch--搜索

    目录 基本知识 查询结果返回设置:版本值.得分限制.定制返回字段 搜索类型 搜索执行偏好 基本查询 过滤器类型 高亮 控制高亮的片段 验证查询 数据排序 查询重写 基本知识 查询结果返回设置:版本值. ...