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


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监听鼠标事件控制textarea输入字符串的个数
Sep 29 Javascript
js实现简单的联动菜单效果
Aug 19 Javascript
JS+CSS实现另类带提示效果的竖向导航菜单
Oct 15 Javascript
JavaScript实现简单Tip提示框效果
Apr 20 Javascript
基于JS实现数字+字母+中文的混合排序方法
Jun 06 Javascript
正则验证小数点后面只能有两位数的方法
Feb 28 Javascript
Vue项目中quill-editor带样式编辑器的使用方法
Aug 08 Javascript
微信小程序仿朋友圈发布动态功能
Jul 15 Javascript
详解ES6 Fetch API HTTP请求实用指南
Nov 14 Javascript
JS实现点击发送验证码 xx秒后重新发送功能
Jul 30 Javascript
vue vantUI tab切换时 list组件不触发load事件的问题及解决方法
Feb 14 Javascript
详解template标签用法(含vue中的用法总结)
Jan 12 Vue.js
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
第八节 访问方式 [8]
2006/10/09 PHP
用Php实现链结人气统计
2006/10/09 PHP
php数组函数序列之in_array() - 查找数组中是否存在指定值
2011/11/07 PHP
cakephp2.X多表联合查询join及使用分页查询的方法
2017/02/23 PHP
YII2.0框架行为(Behavior)深入详解
2019/07/26 PHP
自己整理的一个javascript日期处理函数
2010/10/16 Javascript
选择器中含有空格在使用示例及注意事项
2013/07/31 Javascript
Node.js实现批量去除BOM文件头
2014/12/20 Javascript
纯JS实现旋转图片3D展示效果
2015/04/12 Javascript
深入理解关于javascript中apply()和call()方法的区别
2016/04/12 Javascript
使用jQuery操作DOM的方法小结
2017/02/27 Javascript
AngularJS封装$http.post()实例详解
2017/05/06 Javascript
jQuery序列化后的表单值转换成Json
2017/06/16 jQuery
页面缩放兼容性处理方法(zoom,Firefox火狐浏览器)
2017/08/29 Javascript
jQuery实现注册会员时密码强度提示信息功能示例
2017/09/05 jQuery
Node.js爬取豆瓣数据实例分析
2018/03/05 Javascript
小程序按钮避免多次调用接口和点击方案实现(不用showLoading)
2020/04/15 Javascript
Vue+Bootstrap实现简易学生管理系统
2021/02/09 Vue.js
[06:16]DOTA2守卫传承者——职业选手谈心路历程
2015/02/26 DOTA
使用python将mdb数据库文件导入postgresql数据库示例
2014/02/17 Python
python里将list中元素依次向前移动一位
2014/09/12 Python
python写xml文件的操作实例
2014/10/05 Python
python中assert用法实例分析
2015/04/30 Python
对python中使用requests模块参数编码的不同处理方法
2018/05/18 Python
python 查找文件名包含指定字符串的方法
2018/06/05 Python
编写多线程Python服务器 最适合基础
2018/09/14 Python
用python对excel进行操作(读,写,修改)
2020/12/25 Python
HTML5 虚拟键盘出现挡住输入框的解决办法
2017/02/14 HTML / CSS
塔吉特百货公司官网:Target
2017/04/27 全球购物
房地产出纳岗位职责
2013/12/01 职场文书
电子商务专业自我鉴定
2013/12/18 职场文书
小学毕业感言50字
2014/02/16 职场文书
勤奋学习演讲稿
2014/05/10 职场文书
2014年安全生产大检查方案
2014/05/13 职场文书
Lakehouse数据湖并发控制陷阱分析
2022/03/31 Oracle
Vertica集成Apache Hudi重磅使用指南
2022/03/31 Servers