YClimb 2019-06-25
版权声明:本文为博主原创文章,未经博主允许不得转载。
目前微信官方的微信支付demo没有node版本,这几天一直折腾微信支付,当做笔记记录下来;
参考资料微信支付官方文档
微信支付的签名采用MD5加密,下面微信支付的签名算法,及统一下单:
首先先建立一个wechatPay.js 文件(在该文件中包括签名算法,统一下单等)
/** ** 引入依赖包 **/ var config = require('../config'); var request = require("request"); var moment = require('moment'), _ = require('underscore'), https = require('https'), fs = require('fs'), URL = require('url'), CryptoJS = require("crypto-js"), jsontoxml = require('jsontoxml'), xml2js = require('xml2js'); var crypto = require('crypto'); /** ** 签名算法 **/ var generateSign = exports.genrateSign = function(obj) { var tmpObj = {}; // 取非空的key _.each(obj, function(value, key){ if(value) { tmpObj[key] = value; } }); var keys = _.keys(tmpObj); // key 字典排序 keys = keys.sort(); var tmpArr = []; _.each(keys, function(key) { tmpArr.push(key + "=" + tmpObj[key]) }) tmpArr.push("key=" + config.wxmcn.mcnsecret); // //key为在微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 var tmpStr = tmpArr.join('&'); // 拼接字符串 var sign = crypto.createHash('md5').update(tmpStr, 'utf8').digest('hex'); return sign.toUpperCase(); } //统一下单,获取code_url后期生成二维码 var paysign = exports.paysign = function(params,callback) { if(_.isEmpty(params)) { callback('参数不能为空'); } var currentTime = moment().valueOf().toString(); var nonce_str = [ config.wxmcn.mcnid, currentTime ].join(''); // 随机字符串 var mch_billno = [ config.wxmcn.mcnid, moment().format("YYYYMMDD"), moment().unix() ].join(''); // 订单号 var ret = { appid: config.H5.appid, body: params.body, // 商品描述 attach: params.attach, // 用户的身份intid mch_id: config.wxmcn.mcnid, // 商户号 nonce_str: nonce_str, // 随机字符串 notify_url:params.notify_url, // 通知地址 out_trade_no:mch_billno, // 商户订单号 spbill_create_ip:params.spbill_create_ip, // 终端ip total_fee:params.total_fee, // 标价金额 trade_type:params.trade_type // 交易类型 }; if(!_.isEmpty(params.openid)){ _.extend(ret,{openid: params.openid}); } var sign = generateSign(ret); _.extend(ret,{sign: sign}); var body = jsontoxml(ret); body = '<xml>' + body + '</xml>'; request({ url:'https://api.mch.weixin.qq.com/pay/unifiedorder', method: 'POST', body: body },function (err, response, body) { if (!err && response.statusCode == 200) { // xml2js将返回xml 转换成json,但是后面都是都数组 xml2js.parseString(body, function(err, json) { if (err) { callback(new Error("解析xml报错")); } else { var result = formMessage(json.xml); // 转换成正常的json 数据 if(result.return_code === 'SUCCESS' && result.result_code === 'SUCCESS') { callback(null,result); }else { callback(new Error('wechat err')) } } }) } }); }; // 将xml2js 转换成json数据进一步转换 var formMessage = function(result) { var message = {}; if (typeof result === 'object') { var keys = Object.keys(result); for (var i = 0; i < keys.length; i++) { var item = result[keys[i]]; var key = keys[i]; if (!(item instanceof Array) || item.length === 0) { continue; } if (item.length === 1) { var val = item[0]; if (typeof val === 'object') { message[key] = formMessage(val); } else { message[key] = (val || '').trim(); } } else { message[key] = []; for (var j = 0, k = item.length; j < k; j++) { message[key].push(formMessage(itemp[j])); } } } } return message; }
本次开发用的express框架,创建一个wxpayRouter.js(包括获取微信支付的二维码等)
/* ** 引入依赖 */ var express = require('express'); var wxPayRouter = express.Router(); var mongoose = require('mongoose'), ObjectId = mongoose.Schema.Types.ObjectId; var wechatPay = require('./wechatpay') var URL = require('url'), async = require('async'), _ = require('underscore'), qr = require('qr-image'), jsontoxml = require('jsontoxml'), moment = require('moment'); wxPayRouter.get('/order',function(req, res, next){ var params = URL.parse(req.url, true); var queryParams = req.query; total_fee = queryParams.total_fee; // 前端金额 var status = 400, errmsg = ""; if(_.isEmpty(total_fee)) { errmsg = 'total_fee is empty'; } if(errmsg){ return res.end({status: status, msg: errmsg}); } async.auto({ getCodeUrl: function(callback) { var condition = {body: '订单名称',attach:'附加信息'}; // attach 会在支付成功的后的原封不动的返回 if(!_.isEmpty(total_fee)) { _.extend(condition, {total_fee: total_fee}); } _.extend(condition, {spbill_create_ip: tools.getLocalIP(),trade_type: 'NATIVE'}); // notify_url 为微信回调的地址,将支付成功的信息以数据流的形式返回 _.extend(condition,{notify_url: 'http://49727c15.ngrok.io/wxpay/orderpay'}); wechatPay.paysign(condition, function(err, result){ if(err) { return callback(new Error('connect wechat service is fail')); } callback(null,result ); }); } }, function(err, results) { if(err) { return res.end({status: status, msg: err.message}); } var data = results.getCodeUrl; if(_.isEmpty(data)){ status = 404; }else{ status = 200; } res.end({status: status, data: data}); }) }); module.exports = wxPayRouter;
后台微信的支付接口已经完成,前端调用order接口同时需要将支付金额一并传递过来;然后后台返回相关信息,code_url通过第三方工具生成二维码,用户扫码即可完成支付。