最近公司需要做微信现金红包功能,于是本人根据微信文档(https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3)进行了支付开发。但是其中发现微信文档有太多的坑导致我们根本没法快速实现,为了方便nodejs的小伙伴们快速上手我把我的代码和遇到的坑直接贴上。
1.webpay.js //微信红包方法
/**
* Created by feng on 2018/08/17 /common/weixin.js
*/
/*拼接微信红包xml串 */
var config = require('./config');
var request = require('request');
var xml2js = require('xml2js');
// var xmlreader = require('xmlreader'); //需要安装 xmlreader包
var fs = require('fs');
var https = require('https');
var fnCreateXml = function(json){
var _xml = '';
for(var key in json) {
_xml+= '<'+key+'>'+json[key]+''+key+'>';
}
return _xml;
}
/*
生成url串用于微信md5校验
*/
var fnCreateUrlParam = function(json){
var _str = '';
var _arr = []
for(var key in json){
_arr.push(key+'='+json[key]);
}
return _arr.join('&');
}
/*
生成微信红包数据
*/
var fnGetWeixinBonus = function(option){
// var min_value = req.body.min_value ||10, //红包最小金额
// var max_value = req.body.max_value || 10, //红包最大金额
var total_amount = option.total_amount || 10, //红包总金额
re_openid = option.re_openid || 'oWzhP0R68_eoMM6NvMzRWsx0uesk', //红包发送的目标用户
total_num = option.total_num || 1; //红包个数
var now = new Date();
var showName = config.server.showName;
var clientIp = config.server.clientIp;
var wishing = config.server.wishing;
var mch_id = config.server.mch_id;
var wxappid = config.server.wxappid,
wxkey = config.server.wxkey;
var date_time = now.getFullYear()+''+(now.getMonth()+1)+''+now.getDate();
var date_no = (now.getTime() +'').substr(-8); //生成8为日期数据,精确到毫秒
var random_no = Math.floor(Math.random()*99);
if(random_no < 10){ //生成位数为2的随机码
random_no = '0'+ random_no;
}
var muc_id = mch_id;
var xmlTemplate = '
var contentJson = {};
contentJson.act_name = showName;// '新年红包';
contentJson.client_ip = clientIp;
contentJson.mch_billno = muc_id + date_time+ date_no + random_no; //订单号为 mch_id + yyyymmdd+10位一天内不能重复的数字; //+201502041234567893';
contentJson.mch_id = muc_id;
//contentJson.logo_imgurl = '';
// contentJson.max_value = max_value;//'10';
// contentJson.min_value = min_value;// '10';
contentJson.nick_name = showName;
contentJson.nonce_str = Math.random().toString(36).substr(2, 15);
contentJson.re_openid = re_openid;// 'opVfe0v30XbCW7LE2j-7ruENJFS0'; // 'onqOjjmM1tad-3ROpncN-yUfa6uI';
contentJson.remark = wishing;
contentJson.send_name = showName;//
//contentJson.share_content = '';
//contentJson.share_share_url = '';
//contentJson.share_share_imageurl = '';
contentJson.total_amount = total_amount;// '10';
contentJson.total_num = total_num ;//1;
contentJson.wishing = wishing;//'恭喜发财';
contentJson.wxappid = wxappid;//商户appid
contentJson.key = wxkey;
var contentStr = fnCreateUrlParam(contentJson);
console.log('content='+ contentStr);
var crypto = require('crypto');
contentJson.sign = crypto.createHash('md5').update(contentStr, 'utf8').digest('hex').toUpperCase();
//删除 key (key不参与签名)
delete contentJson.key;
var xmlData = fnCreateXml(contentJson);
var sendData = '
return sendData;
console.log('xml='+ sendData);
}
//得到token的方法
exports.getToken =function(req,res){
var APPID = config.server.wxappid;
var APPSECRET = config.server.appsecret;
var url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+APPID+"&secret="+APPSECRET+"";
request(
{
url : url,
method : 'GET',
body : ''
}, function (err, response, body){
if (!err && response.statusCode == 200){
console.log(body);
res.json({success:true,data: body});//返回客户端数据
}
else{
res.json({success:false});
}
});
}
//得到openid列表的方法
exports.getOpenList =function(req,res){
var access_token = req.params.access_token;
var url = "https://api.weixin.qq.com/cgi-bin/user/get?access_token="+access_token+"&next_openid=";
request(
{
url : url,
method : 'GET',
body : ''
}, function (err, response, body){
if (!err && response.statusCode == 200){
console.log(body);
res.json({success:true,data: body});//返回客户端数据
}
else{
res.json({success:false});
}
});
}
//得到个人openid信息的方法
exports.getUserInfo =function(req,res){
var access_token = req.params.access_token;
var openId = "oWzhP0R68_eoMM6NvMzRWsx0uesk";
var url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="+access_token+"&openid="+ openId +"&lang=zh_CN";
request(
{
url : url,
method : 'GET',
body : ''
}, function (err, response, body){
if (!err && response.statusCode == 200){
console.log(body);
res.json({success:true,data: body});//返回客户端数据
}
else{
res.json({success:false});
}
});
}
//微信现金红包
exports.fnSendMoney = function(req,res,callback){
var host = 'api.mch.weixin.qq.com';
var path = '/mmpaymkttransfers/sendredpack';
var total_amount = req.body.total_amount;
var total_num = 1;
var re_openid = req.body.re_openid;
var opt = {
host: host,
port:'443',
method:'POST',
path: path,
key: fs.readFileSync('./config/apiclient_key.pem'), //将微信生成的证书放入 cert目录下
cert: fs.readFileSync('./config/apiclient_cert.pem')
}
var body = '';
opt.agent = new https.Agent(opt);
var req = https.request(opt, function(res) {
console.log("Got response: " + res.statusCode);
res.on('data',function(d){
body += d;
}).on('end', function(){
//console.log(res.headers);
console.log('微信返回消息');
console.log(body);
var parser = new xml2js.Parser({ trim:true, explicitArray:false, explicitRoot:false });//解析签名结果xml转json
parser.parseString(body, function(err, result){
if(typeof callback == 'function'){
// + result['return_msg']+ result['result_code']
callback(result['return_code']+'|'+ result['return_msg']+'|'+ result['result_code']);
}
});
});
}).on('error', function(e) {
console.log("Got error: " + e.message);
});
var option = {total_amount,re_openid,total_num};
var sendData = fnGetWeixinBonus(option);
req.write(sendData);
req.end();
}
2.config.js 系统参数配置文件
'use strict';
module.exports = {
clientIp:"126.77.66.132",
showName:"天天科技",
wishing:"恭喜发财",
mch_id:"1511515151",
wxkey:"tiantiankeji8888", //key为在微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
appid:"wxefcc9999999999",//微信支付app的appid
wxappid:"wx3a66666666666",//微信公众号appid
appsecret: "wx8888888888888"//公众号secret
};
3.app.js里调用方法:
//微信现金红包
let webpay = require('./modules/webpay');
// 微信现金红包
app.post('/webpay',webpay.fnSendMoney);
//得到访问token接口
app.get('/getToken',webpay.getToken);
//获取公众号下所有关注的openid信息接口
app.get('/getOpenList/:access_token',webpay.getOpenList);
//获取个人信息接口
app.get('/getUserInfo/:access_token',webpay.getUserInfo);