微信小程序开发(五)小程序支付-统一下单
来源:互联网 发布:c语言中运算符优先级 编辑:程序博客网 时间:2024/05/21 10:32
准确来说小程序的支付在上个月就已经做完了,只是那个时候项目原型和UI还没出来就没正式动工。现在项目快做完了,就有时间写博客了。
在做小程序支付希望你已经熟读微信的文档微信支付-小程序-手机端和微信支付-小程序-后台。且你已经有了
AppID: "wx****************", // 小程序ID Secret: "********************************", // 小程序Secret Mch_id: "**********", // 商户号 Mch_key: "********************", // 商户key
关于上面的这4个数据的获取,请自行在自己的账号中获取和设置。且你已经有了用户的openid。《微信小程序开发(四)获取用户openid》。
小程序接口
wx.requestPayment({ 'timeStamp': '', 'nonceStr': '', 'package': '', 'signType': 'MD5', 'paySign': '', 'success':function(res){ }, 'fail':function(res){ }})
小程序接口就暴露这一个方法。这个方法有4个参数是需要后台去获取的。
其实大部分工作都是后台的事情。
后端实现
后端主要是统一下单的这个接口https://api.mch.weixin.qq.com/pay/unifiedorder
。
这里主要就是几个签名算法:
统一下单签名
// 生成签名function paysignjsapi(appid,body,mch_id,nonce_str,notify_url,openid,out_trade_no,spbill_create_ip,total_fee) { var ret = { appid: appid, 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: 'JSAPI' }; var str = raw(ret); str = str + '&key='+key; var md5Str = cryptoMO.createHash('md5').update(str).digest('hex'); md5Str = md5Str.toUpperCase(); return md5Str;};function raw(args) { var keys = Object.keys(args); keys = keys.sort(); var newArgs = {}; keys.forEach(function(key) { newArgs[key.toLowerCase()] = args[key]; }); var str = ''; for(var k in newArgs) { str += '&' + k + '=' + newArgs[k]; } str = str.substr(1); return str;};
小程序paySign
function paysignjs(appid, nonceStr, package, signType, timeStamp) { var ret = { appId: appid, nonceStr: nonceStr, package: package, signType: signType, timeStamp: timeStamp }; var str = raw1(ret); str = str + '&key='+key; return cryptoMO.createHash('md5').update(str).digest('hex');};function raw1(args) { var keys = Object.keys(args); keys = keys.sort() var newArgs = {}; keys.forEach(function(key) { newArgs[key] = args[key]; }); var str = ''; for(var k in newArgs) { str += '&' + k + '=' + newArgs[k]; } str = str.substr(1); return str;};
统一下单后端实现
var wxConfig = require('../wx_pay/wx_x_config'); var cryptoMO = require('crypto'); // MD5算法var parseString = require('xml2js').parseString; // xml转js对象var key = wxConfig.Mch_key;/* * 根据openid 发起微信支付 */router.all('/api/wxpay/unifiedorder', function(req, res, next) { var param = req.query || req.params; var openid = param.openid; var spbill_create_ip = req.ip.replace(/::ffff:/, ''); // 获取客户端ip var body = '测试支付'; // 商品描述 var notify_url = 'https://www.hgdqdev.cn/api/wxpay' // 支付成功的回调地址 可访问 不带参数 var nonce_str = getNonceStr(); // 随机字符串 var out_trade_no = wxConfig.getWxPayOrdrID(); // 商户订单号 var total_fee = '1'; // 订单价格 单位是 分 var timestamp = Math.round(new Date().getTime()/1000); // 当前时间 var bodyData = '<xml>'; bodyData += '<appid>' + wxConfig.AppID + '</appid>'; // 小程序ID bodyData += '<body>' + body + '</body>'; // 商品描述 bodyData += '<mch_id>' + wxConfig.Mch_id + '</mch_id>'; // 商户号 bodyData += '<nonce_str>' + nonce_str + '</nonce_str>'; // 随机字符串 bodyData += '<notify_url>' + notify_url + '</notify_url>'; // 支付成功的回调地址 bodyData += '<openid>' + openid + '</openid>'; // 用户标识 bodyData += '<out_trade_no>' + out_trade_no + '</out_trade_no>'; // 商户订单号 bodyData += '<spbill_create_ip>' + spbill_create_ip + '</spbill_create_ip>'; // 终端IP bodyData += '<total_fee>' + total_fee + '</total_fee>'; // 总金额 单位为分 bodyData += '<trade_type>JSAPI</trade_type>'; // 交易类型 小程序取值如下:JSAPI // 签名 var sign = paysignjsapi( wxConfig.AppID, body, wxConfig.Mch_id, nonce_str, notify_url, openid, out_trade_no, spbill_create_ip, total_fee ); bodyData += '<sign>' + sign + '</sign>'; bodyData += '</xml>'; // 微信小程序统一下单接口 var urlStr = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; request({ url: urlStr, method: 'POST', body: bodyData }, function (error, response, body) { if (!error && response.statusCode == 200) { var returnValue = {}; parseString(body, function (err, result) { if (result.xml.return_code[0] == 'SUCCESS') { returnValue.msg = '操作成功'; returnValue.status = '100'; returnValue.out_trade_no = out_trade_no; // 商户订单号 // 小程序 客户端支付需要 nonceStr,timestamp,package,paySign 这四个参数 returnValue.nonceStr = result.xml.nonce_str[0]; // 随机字符串 returnValue.timestamp = timestamp.toString(); // 时间戳 returnValue.package = 'prepay_id=' + result.xml.prepay_id[0]; // 统一下单接口返回的 prepay_id 参数值 returnValue.paySign = paysignjs(wxConfig.AppID, returnValue.nonceStr, returnValue.package, 'MD5',timestamp); // 签名 res.end(JSON.stringify(returnValue)); } else{ returnValue.msg = result.xml.return_msg[0]; returnValue.status = '102'; res.end(JSON.stringify(returnValue)); } }); } })});
wxConfig代码:
/* 微信参数AppID 和 Secret */var wxConfig = { AppID: "wx****************", // 小程序ID Secret: "********************************", // 小程序Secret Mch_id: "**********", // 商户号 Mch_key: "********************", // 商户key // 生成商户订单号 getWxPayOrdrID: function(){ var myDate = new Date(); var year = myDate.getFullYear(); var mouth = myDate.getMonth() + 1; var day = myDate.getDate(); var hour = myDate.getHours(); var minute = myDate.getMinutes(); var second = myDate.getSeconds(); var msecond = myDate.getMilliseconds(); //获取当前毫秒数(0-999) if(mouth < 10){ /*月份小于10 就在前面加个0*/ mouth = String(String(0) + String(mouth)); } if(day < 10){ /*日期小于10 就在前面加个0*/ day = String(String(0) + String(day)); } if(hour < 10){ /*时小于10 就在前面加个0*/ hour = String(String(0) + String(hour)); } if(minute < 10){ /*分小于10 就在前面加个0*/ minute = String(String(0) + String(minute)); } if(second < 10){ /*秒小于10 就在前面加个0*/ second = String(String(0) + String(second)); } if (msecond < 10) { msecond = String(String(00) + String(second)); } else if(msecond >= 10 && msecond < 100){ msecond = String(String(0) + String(second)); } var currentDate = String(year) + String(mouth) + String(day) + String(hour) + String(minute) + String(second) + String(msecond); return currentDate; }};module.exports = wxConfig;
实例
// 支付按钮点击事件 payTap: function(){ var self = this; wx.request({ url: 'https://www.hgdqdev.cn/api/wxpay/unifiedorder', data: { openid: self.data.openid // 这里正常项目不会只有openid一个参数 }, success: function(res){ if(res.data.status == 100){ var payModel = res.data; wx.requestPayment({ 'timeStamp': payModel.timestamp, 'nonceStr': payModel.nonceStr, 'package': payModel.package, 'signType': 'MD5', 'paySign': payModel.paySign, 'success': function (res) { wx.showToast({ title: '支付成功', icon: 'success', duration: 2000 }) }, 'fail': function (res) { } }) } }, fail: function(){ } }) },
阅读全文
1 0
- 微信小程序开发(五)小程序支付-统一下单
- 微信小程序支付开发笔记2--生成签名-统一下单-二次签名
- 【微信开发】支付-统一下单
- 微信小程序开发(六)小程序支付-notify_url
- 微信小程序开发(七)小程序支付-查询订单
- 微信小程序开发(八)小程序支付-关闭订单
- 微信小程序开发(九)小程序支付-申请退款
- 微信小程序开发(十)小程序支付-查询退款
- 微信小程序和支付宝小程序开发记录
- 微信开发-公众号支付(2)-统一下单
- 微信小程序支付demo, php开发小程序支付接口实例
- 支付宝小程序开发教程一
- thinkphp5+easywechat开发小程序支付
- 支付宝小程序开发教程
- 支付宝小程序开发(一)
- 微信支付-----统一下单action
- 微信支付统一下单
- 微信支付之统一下单
- 【c++基础】8.类和对象——类的实现1
- 第一章 并发编程的挑战
- Kotlin学习笔记之基础语法
- js 倒计时,在html中显示,距离刷新还有几秒
- spring MVC配置详解
- 微信小程序开发(五)小程序支付-统一下单
- python第18篇自己构造一个模块使用
- linux运维-nfs
- 设计模式之工厂方法模式(Factory Method)
- 详解VS2017使用scanf报错的解决方法
- Html5入门
- std::function与std::bind 函数指针
- java.lang.IllegalArgumentException
- Node 学习之Connect模块及其中间件的使用