前提条件html
一、有一个微信开放平台 https://open.weixin.qq.com/node
二、有一个微信公众平台 https://mp.weixin.qq.com 而且开通微信支付小程序
三、有一个微信小程序 https://developers.weixin.qq.com/miniprogram/dev/quickstart/basic/release.html 登录地址同 2 微信公众平台后端
申请过程就不详细说了,准备好各类企业的资质证书,运营执照,企业版 须要对公帐户打款验证 微信小程序
小程序要绑定到公众号,公众号和小程序都要绑定到开放平台api
说一下为何要有这三个平台帐号,原平生台app 拉起微信小程序,受权登录之后取得登陆码,受权登陆官方文档 https://developers.weixin.qq.com/miniprogram/dev/api/wx.login.html服务器
把这个登陆码发送到后端,后端经过这个登陆码+小程序的appid + secret 拿到用户的unionid(小程序 和 公众号 都要绑定了开放平台才会有unionid,同一开放平台下的小程序和公众号unionid相同) 微信
获取unionid官方文档 https://developers.weixin.qq.com/miniprogram/dev/api/code2Session.htmlapp
经过这个unionid来获取到玩家在公众号的openid,微信支付发送红包到玩家帐号上就是经过这个公众号的openid微信公众平台
后端必定要配置一个https的服务器 否则发微信红包的时候 只会收到微信服务器返回 302 not fond
Node 环境https的配置 https://blog.csdn.net/wufaliang003/article/details/77478720
下面直接上代码了
辅助函数部分
let crypto = require("crypto"); exports.MgetMD5 = function(str){ let hash = crypto.createHash('md5'); let md5Value = hash.update(str).digest("hex"); return md5Value.toUpperCase() } exports.MgetSHA256 = function(str,key){ let hmac = crypto.createHmac('sha256',key); let shaValue = hmac.update(str).digest("hex"); return shaValue.toUpperCase(); } let charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklnmopqrstuvwxyz0123456789"; //返回随机字符串 exports.MgetRandomStr = function(length){ if (length){ length = Math.round(length); } else{ length = Math.round(Math.random()*20 + 12) } let range = charSet.length; let result = ''; let position = 0; for(let i = 0; i < length; i++) { position = Math.floor(Math.random()*range); result += charSet[position]; } return result; } //返回随机数字字符串 exports.MgetRandomNumber = function(length){ let numbers = '0123456789'; length = length ? length : 10; let range = numbers.length; let result = ''; let position = 0; for(let i = 0; i < length; i++) { position = Math.floor(Math.random()*range); result += numbers[position]; } return result; } //返回给定宽度的数字字符串 exports.MgetFixedNumber = function(number,width){ width = width ? width : 2; let fixedNumber = number.toString(); for(; fixedNumber.length < width ; ){ fixedNumber = "0" + fixedNumber; } return fixedNumber; } //返回 对象属性排序后的全部键和值拼接在在一块儿的字符串 exports.MgetSortedParameter = function(parameterObject){ let attributes = []; parameterObject = parameterObject ? parameterObject:{}; for(let attr in parameterObject){ attributes.push(attr); } attributes.sort(); let paramStr = ""; attributes.forEach(element=>{ paramStr += element + "=" + parameterObject[element] + "&" }); return paramStr; }
发送红包部分
//构造订单号 function getOrderID(){ let currentDate = new Date(); let year = currentDate.getFullYear(); let month = currentDate.getMonth() month = month >= 9 ? month + 1 : '0'+(month + 1); let day = currentDate.getDate() day = mutils.MgetFixedNumber(day); //mch_id 是微信支付分配的商户号 let orderid = mch_id + year + month + day + mutils.MgetRandomNumber(); return orderid; } //发红包 function makeHongBao(openid,res){ //设置参数模型 let ParamModel = {}; ParamModel["nonce_str"] = mutils.MgetRandomStr();//随机字符串,不长于32位 ParamModel["wxappid"] = gzh_appid;//公众帐号appid ParamModel["mch_id"] = mch_id;//商户号 微信支付分配的商户号 申请中 ParamModel["mch_billno"] = getOrderID();//商户订单号 字母加数字构成 长度最多28位且必须惟一 ParamModel["send_name"] = "商户名称";//商户名称 红包发送者名称 ParamModel["re_openid"] = "otWaQ0ztsh9p6X4ZQVMzNa17sTpQ"//公众号下 用户openid ParamModel["total_amount"] = 100;//付款金额,单位分 ParamModel["total_num"] = 1;//红包发放总个数 ParamModel["wishing"] = "感谢您使用XXX,祝您旗开得胜!";//红包祝福语 最大长度128位 ParamModel["client_ip"] = "125.120.226.214";//调用接口的机器Ip地址 ParamModel["act_name"] = "分享送红包";//活动名称 ParamModel["remark"] = "分享越多送得越多";//备注信息 ParamModel["scene_id"] = "PRODUCT_5";// 非必须 PRODUCT_6 渠道分润 红包金额大于200或者小于1元时必传 PRODUCT_1 //ParamModel["notify_way"] ="JSAPI";//通知用户形式 ------------- 小程序红包参数? //ParamModel["risk_info"] = "posttime%3d123123412%26clientversion%3d234134%26mobile%3d122344545%26deviceid%3dIOS";//活动信息 非必须 let attrStr = mutils.MgetSortedParameter(ParamModel); attrStr += "key=" + mch_key//key为商户平台设置的密钥key ParamModel["sign"] = mutils.MgetMD5(attrStr); //构造POST参数xml let contents = '<xml>'; for( let attr in ParamModel){ contents += makeXMLNode(attr,ParamModel[attr],false); } contents += '</xml>'; //配置请求选项 let options = { host:'api.mch.weixin.qq.com', port:443, path:'/mmpaymkttransfers/sendredpack', key:fs.readFileSync(__dirname + '/cert/apiclient_key.pem'), cert:fs.readFileSync(__dirname + '/cert/apiclient_cert.pem'), method:'POST' } options.agent = new https.Agent(options); //发送Post请求 var request = https.request(options, function(response){ response.setEncoding('utf8'); response.on('data',function(data){ console.log("data:",data); res.end("wait to do !"); }); }); request.write(contents); request.end(); request.on('error',function(err){ console.log(err) }) } function makeXMLNode(nodeName,Value,bCTata){ if (bCTata){ return '<' + nodeName + '><![CDATA[' + Value + ']]></' + nodeName + '>' } return '<' + nodeName + '>' + Value + '</' + nodeName + '>' }
如何获取到公众号的openid
一、后台经过公众号的的appid 和 secret(须要本身设置) 获取到access_token 官方文档 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183
二、批量获取到关注公众号的的用户信息 注意一次最多获取一百条 官方文档 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140839
三、把前面提到的unionid 拿来依次和用户信息里面的unionid比对 若是相同说明找到正确的用户了就取它的openid ,就能够根据这个openid发红包了
写得感受有点乱,主要是参考思路,过程比较坑 + 各类扫二维码 输验证码
node 服务器若是是在外网有固定ip地址,listen函数就不要填ip地址了,否则会报错