微信小程序 在线支付功能的实现


Posted in Javascript onMarch 14, 2017

微信小程序 在线支付功能

最近需要在微信小程序中用到在线支付功能,于是看了一下官方的文档,发现要在小程序里实现微信支付还是很方便的,如果你以前开发过服务号下的微信支付,那么你会发现其实小程序里的微信支付和服务号里的开发过程如出一辙,下面我就具体说一下小程序里微信支付的开发流程和注意点。

微信小程序 在线支付功能的实现

1.开通微信支付和微信商户号

这个过程就和开通服务号的微信支付过程一样,没有什么可以说的。

微信小程序 在线支付功能的实现

2.获得用户的openid

首页我们需要在小程序的客户端js中获取当前用户的openid,通过调用wx.login方法可以得到用户的code,然后开发者服务器使用登录凭证 code 获取 openid。

wx.login({
   success: function(res) {
    if (res.code) {
     //发起网络请求
     wx.request({
      url: 'https://yourwebsit/onLogin',
      method: 'POST',
      data: {
       code: res.code
      },
      success: function(res) {
        var openid = res.data.openid;
      },
      fail: function(err) {
        console.log(err)
      }
     })
    } else {
     console.log('获取用户登录态失败!' + res.errMsg)
    }
   }
  });
var code = req.param("code");
    request({
      url: "https://api.weixin.qq.com/sns/jscode2session?appid="+appid+"&secret="+secret+"&js_code="+code+"&grant_type=authorization_code",
      method: 'GET'
    }, function(err, response, body) {
      if (!err && response.statusCode == 200) {
        res.json(JSON.parse(body));
      }
    });

3.获取prepay_id和支付签名验证paySign

这一步的过程就和服务号里的微信支付过程一样,分为客户端和服务器端

首先来看一下客户端js

在服务号里,我们是通过如下的代码来调起支付功能

function jsApiCall()
    {
      WeixinJSBridge.invoke(
        'getBrandWCPayRequest',
        {
          "appId":"",   //公众号名称,由商户传入   
          "timeStamp":"",     //时间戳,自1970年以来的秒数   
          "nonceStr":"", //随机串   
          "package":"prepay_id=<%=prepay_id%>",   
          "signType":"MD5",     //微信签名方式:   
          "paySign":"<%=_paySignjs%>" //微信签名
        },
        function(res){
          WeixinJSBridge.log(res.err_msg);
          if( res.err_msg =="get_brand_wcpay_request:ok"){
            alert("支付成功!");
          }else{
            alert("支付失败!");
          }
        }
      );
    }

在小程序里,我们是通过wx.requestPayment方法来调起支付功能,当然在这之前,我们先要获取prepay_id。

wx.request({
          url: 'https://yourwebsit/service/getPay', 
          method: 'POST',
          data: {
           bookingNo:bookingNo, /*订单号*/
           total_fee:total_fee,  /*订单金额*/
           openid:openid
          },
          header: {
            'content-type': 'application/json'
          },
          success: function(res) {
            wx.requestPayment({
             'timeStamp':timeStamp,
             'nonceStr': nonceStr,
             'package': 'prepay_id='+res.data.prepay_id,
             'signType': 'MD5',
             'paySign': res.data._paySignjs,
             'success':function(res){
               console.log(res);
             },
             'fail':function(res){
               console.log('fail:'+JSON.stringify(res));
             }
            })
          },
          fail: function(err) {
            console.log(err)
          }
        })

那在服务器端主要要实现的是prepay_id的获取和签名paySign

var bookingNo = req.param("bookingNo");
    var total_fee = req.param("total_fee");
    var openid = req.param("openid");
    var body = "费用说明";
    var url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    var formData = "<xml>";
    formData += "<appid>appid</appid>"; //appid
    formData += "<attach>test</attach>";
    formData += "<body>" + body + "</body>";
    formData += "<mch_id>mch_id</mch_id>"; //商户号
    formData += "<nonce_str>nonce_str</nonce_str>";
    formData += "<notify_url>notify_url</notify_url>";
    formData += "<openid>" + openid + "</openid>";
    formData += "<out_trade_no>" + bookingNo + "</out_trade_no>";
    formData += "<spbill_create_ip>spbill_create_ip</spbill_create_ip>";
    formData += "<total_fee>" + total_fee + "</total_fee>";
    formData += "<trade_type>JSAPI</trade_type>";
    formData += "<sign>" + paysignjsapi(appid, attach, body, mch_id, nonce_str, notify_url, openid, bookingNo, spbill_create_ip, total_fee, 'JSAPI') + "</sign>";
    formData += "</xml>";
    request({
      url: url,
      method: 'POST',
      body: formData
    }, function(err, response, body) {
      if(!err && response.statusCode == 200) {
        var prepay_id = getXMLNodeValue('prepay_id', body.toString("utf-8"));
        var tmp = prepay_id.split('[');
        var tmp1 = tmp[2].split(']');
        //签名
        var _paySignjs = paysignjs(appid, mch_id, 'prepay_id=' + tmp1[0], 'MD5',timeStamp);
        var o = {
          prepay_id: tmp1[0],
          _paySignjs: _paySignjs
        }
        res.send(o);
      }
    });

下面是用到的函数

function paysignjs(appid, nonceStr, package, signType, timeStamp) {
  var ret = {
    appId: appid,
    nonceStr: nonceStr,
    package: package,
    signType: signType,
    timeStamp: timeStamp
  };
  var string = raw1(ret);
  string = string + '&key='+key;
  console.log(string);
  var crypto = require('crypto');
  return crypto.createHash('md5').update(string, 'utf8').digest('hex');
};

function raw1(args) {
  var keys = Object.keys(args);
  keys = keys.sort()
  var newArgs = {};
  keys.forEach(function(key) {
    newArgs[key] = args[key];
  });

  var string = '';
  for(var k in newArgs) {
    string += '&' + k + '=' + newArgs[k];
  }
  string = string.substr(1);
  return string;
};

function paysignjsapi(appid, attach, body, mch_id, nonce_str, notify_url, openid, out_trade_no, spbill_create_ip, total_fee, trade_type) {
  var ret = {
    appid: appid,
    attach: attach,
    body: body,
    mch_id: mch_id,
    nonce_str: nonce_str,
    notify_url: notify_url,
    openid: openid,
    out_trade_no: out_trade_no,
    spbill_create_ip: spbill_create_ip,
    total_fee: total_fee,
    trade_type: trade_type
  };
  var string = raw(ret);
  string = string + '&key='+key;
  var crypto = require('crypto');
  return crypto.createHash('md5').update(string, 'utf8').digest('hex');
};

function raw(args) {
  var keys = Object.keys(args);
  keys = keys.sort()
  var newArgs = {};
  keys.forEach(function(key) {
    newArgs[key.toLowerCase()] = args[key];
  });

  var string = '';
  for(var k in newArgs) {
    string += '&' + k + '=' + newArgs[k];
  }
  string = string.substr(1);
  return string;
};

function getXMLNodeValue(node_name, xml) {
  var tmp = xml.split("<" + node_name + ">");
  var _tmp = tmp[1].split("</" + node_name + ">");
  return _tmp[0];
}

这样简单3步,小程序的微信支付功能就接上了,下面是测试的支付效果图

微信小程序 在线支付功能的实现

微信小程序 在线支付功能的实现

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

Javascript 相关文章推荐
怎么清空javascript数组
May 11 Javascript
jquery 按钮状态效果 正常、移上、按下
Aug 12 Javascript
jQuery中on()方法用法实例
Jan 19 Javascript
jQuery实现仿淘宝带有指示条的图片转动切换效果完整实例
Mar 04 Javascript
javascript实现判断鼠标的状态
Jul 10 Javascript
js实现用户离开页面前提示是否离开此页面的方法(包括浏览器按钮事件)
Jul 18 Javascript
jQuery实现的漂亮表单效果代码
Aug 18 Javascript
Three.js学习之Lamber材质和Phong材质
Aug 04 Javascript
vue.js开发环境搭建教程
May 04 Javascript
12个非常有用的JavaScript技巧
May 17 Javascript
一个有意思的鼠标点击文字特效jquery代码
Sep 23 jQuery
vue watch深度监听对象实现数据联动效果
Aug 16 Javascript
JS和canvas实现俄罗斯方块
Mar 14 #Javascript
Vue + Webpack + Vue-loader学习教程之相关配置篇
Mar 14 #Javascript
canvas实现刮刮卡效果
Mar 14 #Javascript
Vue + Webpack + Vue-loader学习教程之功能介绍篇
Mar 14 #Javascript
jQuery插件HighCharts绘制的2D堆柱状图效果示例【附demo源码下载】
Mar 14 #Javascript
jQuery插件HighCharts实现的2D堆条状图效果示例【附demo源码下载】
Mar 14 #Javascript
前端框架学习总结之Angular、React与Vue的比较详解
Mar 14 #Javascript
You might like
BBS(php &amp; mysql)完整版(七)
2006/10/09 PHP
php function用法如何递归及return和echo区别
2014/03/07 PHP
php打开本地exe程序,js打开本地exe应用程序,并传递相关参数方法
2018/02/06 PHP
javascript 弹出窗口中是否显示地址栏的实现代码
2011/04/14 Javascript
了不起的node.js读书笔记之node.js中的特性
2014/12/22 Javascript
javascript操作表格排序实例分析
2015/05/06 Javascript
详解iframe与frame的区别
2016/01/13 Javascript
JavaScript实现给定时间相加天数的方法
2016/01/25 Javascript
jQuery on()方法绑定动态元素的点击事件无响应的解决办法
2016/07/07 Javascript
javascript跨域请求包装函数与用法示例
2016/11/03 Javascript
Three.js基础学习之场景对象
2017/09/27 Javascript
NodeJS简单实现WebSocket功能示例
2018/02/10 NodeJs
Vue官方推荐AJAX组件axios.js使用方法详解与API
2018/10/09 Javascript
vue setInterval 定时器失效的解决方式
2020/07/30 Javascript
vue组件添加事件@click.native操作
2020/10/30 Javascript
VUE项目实现主题切换的多种方法
2020/11/26 Vue.js
JS如何实现在弹出窗口中加载页面
2020/12/03 Javascript
python使用wmi模块获取windows下的系统信息 监控系统
2015/10/27 Python
举例讲解Python中的list列表数据结构用法
2016/03/12 Python
两个命令把 Vim 打造成 Python IDE的方法
2016/03/20 Python
Python代码解决RenderView窗口not found问题
2016/08/28 Python
python嵌套字典比较值与取值的实现示例
2017/11/03 Python
python 中不同包 类 方法 之间的调用详解
2020/03/09 Python
Python利用pip安装tar.gz格式的离线资源包
2020/09/14 Python
如何使用PHP session
2015/04/21 面试题
医务工作者先进事迹材料
2014/01/26 职场文书
社区八一活动方案
2014/02/03 职场文书
“学雷锋活动月”总结
2014/03/09 职场文书
关于感恩的演讲稿200字
2014/08/26 职场文书
竞选学习委员演讲稿
2014/09/01 职场文书
授权收款委托书范本
2014/10/10 职场文书
云南省召开党的群众路线教育实践活动总结会议新闻稿
2014/10/21 职场文书
2016年“节能宣传周”活动总结
2016/04/05 职场文书
关于办理居住证的介绍信模板
2019/11/27 职场文书
python实现三阶魔方还原的示例代码
2021/04/28 Python
MySQL数据迁移相关总结
2021/04/29 MySQL