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


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 相关文章推荐
基于jquery tab切换(防止页面刷新)
May 23 Javascript
jquery实现简单易懂的图片展示小例子
Nov 21 Javascript
JavaScript中绑定事件的三种方式及去除绑定
Nov 05 Javascript
将json转换成struts参数的方法
Nov 08 Javascript
jQuery html表格排序插件tablesorter使用方法详解
Feb 10 Javascript
详解vue-cli 接口代理配置
Dec 13 Javascript
thinkjs微信中控之微信鉴权登陆的实现代码
Aug 08 Javascript
JavaScript在web自动化测试中的作用示例详解
Aug 25 Javascript
JavaScript如何把两个数组对象合并过程解析
Oct 10 Javascript
微信小程序实现录音功能
Nov 22 Javascript
详解如何在JS代码中消灭for循环
Dec 11 Javascript
JS数组去重详情
Nov 07 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
德劲1104的电路分析与改良
2021/03/01 无线电
PHP读取MySQL数据代码
2008/06/05 PHP
PHP 日志缩略名的创建函数代码
2010/05/26 PHP
php 注册时输入信息验证器的实现详解
2013/07/05 PHP
PHP7 整型处理机制修改
2021/03/09 PHP
几款极品的javascript压缩混淆工具
2007/05/16 Javascript
javascript 解析后的xml对象的读取方法细解
2009/07/25 Javascript
javascript游戏开发之《三国志曹操传》零部件开发(二)人物行走的实现
2013/01/23 Javascript
jquery中插件实现自动添加用户的具体代码
2013/11/15 Javascript
技术男用来对妹子表白的百度首页
2014/07/23 Javascript
常见的jQuery选择器汇总
2014/11/24 Javascript
NodeJS中利用Promise来封装异步函数
2015/02/25 NodeJs
ECMA5数组的新增方法有哪些及forEach()模仿实现
2015/11/03 Javascript
jQuery实现移动端Tab选项卡效果
2017/03/15 Javascript
Windows下快速搭建NodeJS本地服务器的步骤
2017/08/09 NodeJs
js定时器+简单的动画效果实例
2017/11/10 Javascript
初识 Vue.js 中的 *.Vue文件
2017/11/22 Javascript
jQuery实现的电子时钟效果完整示例
2018/04/28 jQuery
vue2.0页面前进刷新回退不刷新的实现方法
2018/07/31 Javascript
bootstrap模态框关闭后清除模态框的数据方法
2018/08/10 Javascript
脚手架vue-cli工程webpack的作用和特点
2018/09/29 Javascript
深入理解JavaScript 中的执行上下文和执行栈
2018/10/23 Javascript
解决Angularjs异步操作后台请求用$q.all排列先后顺序问题
2019/11/29 Javascript
[03:21]辉夜杯主赛事 12月25日TOP5
2015/12/26 DOTA
[41:52]2018DOTA2亚洲邀请赛3月29日小组赛B组Effect VS Secret
2018/03/30 DOTA
探索Python3.4中新引入的asyncio模块
2015/04/08 Python
手把手教你用python抢票回家过年(代码简单)
2018/01/21 Python
详解Python sys.argv使用方法
2019/05/10 Python
详解Python3中setuptools、Pip安装教程
2019/06/18 Python
Python基于pip实现离线打包过程详解
2020/05/15 Python
英国马莎百货官网:Marks & Spencer
2016/07/29 全球购物
L’Artisan Parfumeur官网:法国香水品牌
2020/08/11 全球购物
毕业生自荐书
2014/02/03 职场文书
项目工作说明书
2014/07/29 职场文书
求职自我推荐信
2015/03/24 职场文书
微软Win11 全新照片应用面向 Dev预览版推出 新版本上手体验图集
2022/09/23 数码科技