1. 程式人生 > >小程式發微信紅包後端Nodejs實現

小程式發微信紅包後端Nodejs實現

前提條件

1、有一個微信開放平臺 https://open.weixin.qq.com/

2、有一個微信公眾平臺 https://mp.weixin.qq.com  並且開通微信支付

3、有一個微信小程式 https://developers.weixin.qq.com/miniprogram/dev/quickstart/basic/release.html 登陸地址同 2 微信公眾平臺

申請過程就不詳細說了,準備好各種企業的資質證書,運營執照,企業版 需要對公賬戶打款驗證 

小程式要繫結到公眾號,公眾號和小程式都要繫結到開放平臺

說一下為什麼要有這三個平臺賬號,原生平臺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.html

通過這個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

1、後臺通過公眾號的的appid 和 secret(需要自己設定) 獲取到access_token 官方文件 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183

2、批量獲取到關注公眾號的的使用者資訊 注意一次最多獲取一百條  官方文件 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140839

3、把前面提到的unionid 拿來依次和使用者資訊裡面的unionid比對 如果相同說明找到正確的使用者了就取它的openid ,就可以根據這個openid發紅包了

寫得感覺有點亂,主要是參考思路,過程比較坑 + 各種掃二維碼 輸驗證碼

node 伺服器如果是在外網有固定ip地址,listen函式就不要填ip地址了,不然會報錯