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


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高亮效果的二种实现方法
Sep 14 Javascript
javascript学习笔记(十) js对象 继承
Jun 19 Javascript
JavaScript实现多维数组的方法
Nov 20 Javascript
js select option对象小结
Dec 20 Javascript
window resize和scroll事件的基本优化思路
Apr 29 Javascript
javascript中for/in循环及使用技巧
Sep 01 Javascript
JS实现可点击展开与关闭的左侧广告代码
Sep 02 Javascript
jquery插件uploadify实现带进度条的文件批量上传
Dec 13 Javascript
AngularJS教程 ng-style 指令简单示例
Aug 03 Javascript
微信小程序 label 组件详解及简单实例
Jan 10 Javascript
用jQuery旋转插件jqueryrotate制作转盘抽奖
Feb 10 Javascript
vue 请求后台数据的实例代码
Jun 22 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 购物车的例子
2009/05/04 PHP
PHP压缩html网页代码(清除空格,换行符,制表符,注释标记)
2012/04/02 PHP
基于php验证码函数的使用示例
2013/05/03 PHP
PHP图像处理之使用imagecolorallocate()函数设置颜色例子
2014/11/19 PHP
php搜索文件程序分享
2015/10/30 PHP
php实现大文件断点续传下载实例代码
2019/10/01 PHP
jQuery获取Select选择的Text和Value(详细汇总)
2013/01/25 Javascript
原生js结合html5制作小飞龙的简易跳球
2015/03/30 Javascript
举例讲解JavaScript中将数组元素转换为字符串的方法
2015/10/25 Javascript
完善的jquery处理机制
2016/02/21 Javascript
详解JS-- 浮点数运算处理
2016/11/28 Javascript
bootstrap手风琴制作方法详解
2017/01/11 Javascript
JS简单获取当前日期和农历日期的方法
2017/04/17 Javascript
详解AngularJs ui-router 路由的简单介绍
2017/04/26 Javascript
利用Mongoose让JSON数据直接插入或更新到MongoDB
2017/05/03 Javascript
React Native时间转换格式工具类分享
2017/10/24 Javascript
vue复合组件实现注册表单功能
2017/11/06 Javascript
浅谈vue,angular,react数据双向绑定原理分析
2017/11/28 Javascript
mpvue小程序仿qq左滑置顶删除组件
2018/08/03 Javascript
vue 中使用 watch 出现了如下的报错的原因分析
2019/05/21 Javascript
JavaScript使用面向对象实现的拖拽功能详解
2019/06/12 Javascript
Python OpenCV实现图片上输出中文
2018/01/22 Python
Python学习笔记之open()函数打开文件路径报错问题
2018/04/28 Python
python发送告警邮件脚本
2018/09/17 Python
python解压TAR文件至指定文件夹的实例
2019/06/10 Python
python GUI库图形界面开发之PyQt5打印控件QPrinter详细使用方法与实例
2020/02/28 Python
Python3安装模块报错Microsoft Visual C++ 14.0 is required的解决方法
2020/07/28 Python
世界上第一个水枕头:Mediflow
2018/12/06 全球购物
盛大笔试题
2016/11/05 面试题
保险公司早会主持词
2014/03/22 职场文书
《月球之谜》教学反思
2014/04/10 职场文书
毕业生找工作自荐书
2014/06/30 职场文书
爱祖国爱家乡演讲稿
2014/09/02 职场文书
小学感恩节活动策划方案
2014/10/06 职场文书
社区党的群众路线教育实践活动剖析材料
2014/10/09 职场文书
电话营销开场白
2015/05/29 职场文书