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


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 相关文章推荐
又一个图片自动缩小的JS代码
Mar 10 Javascript
浅谈javascript中replace()方法
Nov 10 Javascript
Javascript模仿淘宝信用评价实例(附源码)
Nov 26 Javascript
jquery实现全屏滚动
Dec 28 Javascript
JavaScript数组的栈方法与队列方法详解
May 26 Javascript
javascript类型系统_正则表达式RegExp类型详解
Jun 24 Javascript
原生ajax处理json格式数据的实例代码
Dec 25 Javascript
jQuery中页面返回顶部的方法总结
Dec 30 Javascript
jQuery插件HighCharts绘制2D带有Legend的饼图效果示例【附demo源码下载】
Mar 10 Javascript
详解webpack 配合babel 将es6转成es5 超简单实例
May 02 Javascript
PHP 实现一种多文件上传的方法
Sep 20 Javascript
详解Node使用Puppeteer完成一次复杂的爬虫
Apr 18 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
php中simplexml_load_string使用实例分享
2014/02/13 PHP
PHP中常用的输出函数总结
2014/09/22 PHP
php函数连续调用实例分析
2015/07/30 PHP
Laravel5.1自定义500错误页面示例
2016/10/09 PHP
PHP编程实现微信企业向用户付款的方法示例
2017/07/26 PHP
各浏览器对click方法的支持差异小结
2011/07/31 Javascript
动态的绑定事件addEventListener方法的使用
2014/01/24 Javascript
jQuery插件formValidator自定义函数扩展功能实例详解
2015/11/25 Javascript
为jQuery-easyui的tab组件添加右键菜单功能的简单实例
2016/10/10 Javascript
微信小程序 MD5加密登录密码详解及实例代码
2017/01/12 Javascript
javascript 删除数组元素和清空数组的简单方法
2017/02/24 Javascript
jQuery导航条固定定位效果实例代码
2017/05/26 jQuery
基于JQuery的Ajax方法使用详解
2017/08/16 jQuery
javaScript实现鼠标在文字上悬浮时弹出悬浮层效果
2020/04/12 Javascript
Vue多系统切换实现方案
2018/06/05 Javascript
为什么要使用Vuex的介绍
2019/01/19 Javascript
JavaScript禁用右键单击优缺点分析
2019/01/20 Javascript
[22:07]DOTA2-DPC中国联赛 正赛 iG vs Magma 选手采访
2021/03/11 DOTA
Python中删除文件的程序代码
2011/03/13 Python
python的描述符(descriptor)、装饰器(property)造成的一个无限递归问题分享
2014/07/09 Python
Python实现把数字转换成中文
2015/06/29 Python
使用TensorFlow搭建一个全连接神经网络教程
2020/02/06 Python
python def 定义函数,调用函数方式
2020/06/02 Python
python利用google翻译方法实例(翻译字幕文件)
2020/09/21 Python
详解Python流程控制语句
2020/10/28 Python
pycharm 实现调试窗口恢复
2021/02/05 Python
韩国演唱会订票网站:StubHub韩国
2019/01/17 全球购物
网络安全方面的面试题
2015/11/04 面试题
什么样的创业计划书可行性高?
2014/02/01 职场文书
淘宝店策划方案
2014/06/07 职场文书
学校四风问题对照检查材料思想汇报
2014/09/26 职场文书
教师自查自纠材料
2014/10/14 职场文书
销售2014年度工作总结
2014/12/08 职场文书
毕业论文致谢部分怎么写
2015/05/14 职场文书
分享3个非常实用的 Python 模块
2022/03/03 Python
为自由献出你的心脏!「进击的巨人展 FINAL」2022年6月在台开展
2022/04/13 日漫