前提條件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地址了,否則會報錯