node 微信小程式支付
阿新 • • 發佈:2018-12-29
Node 微信支付
說明
因為最近第一次完成微信支付和提現,遇到了很多問題,自己記性又差所以記錄一下.該篇只是node後端流程,申請支付功能或是前端程式碼沒有且為小程式支付:
第一次寫一定不會很好,如果遇到問題 可以加我qq 798474927
業務流程
簽名
簽名應該是最核心的一步,並且只有這一步哈哈哈~~~~~~~所以我們要寫一個簽名的介面:
//支付訂單
exports.miniPay = function(req,res) {
let payData = req.body;
let openId = payData.openId; //trade_type=JSAPI,此引數必傳,使用者在商戶appid下的唯一標識。
let appid = payData.appid; //微信分配的小程式ID
let attach = payData.attach; //附加資料,在查詢API和支付通知中原樣返回,可作為自定義引數使用。
let mch_id = payData.mch_id; //微信支付分配的商戶號
let nonce_str = Math.random ().toString(36).substr(2, 15); //隨機字串,長度要求在32位以內。
let body = payData.body; //商品描述
let out_trade_no = payData.orderNumber; //商戶系統內部訂單號,要求32個字元內,只能是數字、大小寫字母_-|*@ ,且在同一個商戶號下唯一
let total_fee = payData.total_fee; //金額 分為單位
let spbill_create_ip = "123.12.12.123"; //亂寫的
let notify_url = "http://192.168.1.141"; //亂寫的
let trade_type = "JSAPI"; //小程式為JSAPI
let timeStamp = wxPay.time(); //時間戳
/*該方法為第一次簽名方法,微信簽名共有兩次
後面我會將該方法貼出來wxPay.paysignMini
這個是第一次簽名,簽名規則按照文件
*/
let sign = wxPay.paysignMini(appid,mch_id,body,nonce_str,openId,trade_type,notify_url,spbill_create_ip,out_trade_no,total_fee,attach);
let formData = "<xml>";
formData += "<appid>"+appid+"</appid>";
formData += "<attach>"+attach+"</attach>";
formData += "<body>"+body+"</body>";
formData += "<mch_id>"+mch_id+"</mch_id>";
formData += "<nonce_str>"+nonce_str+"</nonce_str>";
formData += "<notify_url>"+notify_url+"</notify_url>";
formData += "<openid>"+openId+"</openid>";
formData += "<out_trade_no>"+out_trade_no+"</out_trade_no>";
formData += "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>";
formData += "<total_fee>"+total_fee+"</total_fee>";
formData += "<trade_type>"+trade_type+"</trade_type>";
formData += "<sign>"+sign+"</sign>";
formData += "</xml>";
/*簽名成功之後,變成xml格式的資料,向微信伺服器傳送https請求,若成功,微信伺服器會返回xml格式資料
解析之後會得到預付交易回話表示prepay_id
在下嗎的方法中用到了兩個封裝的方法,之後會貼出來wxPay.getXMLNodeValue(因為微信返回的是xml形式的所以要寫一個解析的方法),wxPay.paysignMini2(第二次簽名的方法,然後後端就應該沒啥事了)
*/
//!!!!!!!!!!!!!這裡要注意package這個引數 一定要prepay_id=字串與prepay_id進行拼接
request({
url: "https://api.mch.weixin.qq.com/pay/unifiedorder",
method: 'POST',
body: formData
}, function (err, response, body) {
if (!err && response.statusCode == 200) {
let msg = wxPay.getXMLNodeValue('return_msg', body.toString('utf-8')); // 這個引數可選,微信給咱們正確或錯誤資訊
let prepay_id = wxPay.getXMLNodeValue('prepay_id', body.toString('utf-8'));
let nonce_str = wxPay.getXMLNodeValue('nonce_str', body.toString('utf-8'));
let package = 'prepay_id='+prepay_id;
timeStamp = timeStamp.toString();
let paySign= wxPay.paysignMini2(appid,nonce_str,package,timeStamp);
let data = {
msg :msg,
nonce_str:nonce_str,
prepay_id:prepay_id,
timeStamp:timeStamp,
paySign:paySign
};
res.json(data)
}});
};
//好啦 咱們就沒啥事了
輔助方法
之前我們好像就提到了三個方法 在這裡寫一下
wxPay.paysignMini() ,wxPay.getXMLNodeValue() wxPay.paysignMini2()
簽名介面教研工具
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1
如果是簽名錯誤,一定要仔細看看自己引數,平常心 ~~~~
//
exports.paysignMini = (appid,mch_id,body,nonce_str,openId,trade_type,notify_url,spbill_create_ip,out_trade_no,total_fee,attach)=> {
let rets = {
appid: appid,
body: body,
mch_id: mch_id,
nonce_str:nonce_str,
openid:openId,
trade_type:trade_type,
notify_url:notify_url,
spbill_create_ip:spbill_create_ip,
out_trade_no:out_trade_no,
total_fee:total_fee,
attach:attach
};
key = "********************"; //金鑰
var str = raw(rets);
//將引數拼接成字串
str = str + '&key='+key;
var md5Str = crypto.createHash('md5').update(str).digest('hex');
md5Str = md5Str.toUpperCase();
return md5Str;
};
//二次簽名sign
exports.paysignMini2 =(appid,nonceStr,package,timeStamp)=> {
let reta = {
appId: appid,
nonceStr: nonceStr,
package:package,
signType: 'MD5',
timeStamp:timeStamp.toString()
};
key = "**********************"; //金鑰
var str = raw1(reta);
//將引數拼接成字串
str = str + '&key='+key;
console.log("MD5Str:",str);
var md5Str = crypto.createHash('md5').update(str).digest('hex');
md5Str = md5Str.toUpperCase();
return md5Str;
};
exports.getXMLNodeValue = (node_name,xml)=>{
let tmp = xml.split("<"+node_name+">");
if(tmp[1]!=undefined){
let _tmp = tmp[1].split("</"+node_name+">");
let tmp1 = _tmp[0].split('[');
let _tmp1 = tmp1[2].split(']');
return _tmp1[0];
}
};
function raw(args) {
var keys = Object.keys(args);
keys = keys.sort();
var newArgs = {};
keys.forEach(function (key) {
// newArgs[key.toLowerCase()] = args[key];
newArgs[key] = args[key]; });
var str = '';
for (var k in newArgs) {
str += '&' + k + '=' + newArgs[k];
}
str = str.substr(1);
console.log(str)
return str;
}
結束:
如果只是單純的支付,我們這裡已經算是完成了.但是 支付成功之後驗證是不可少的一步.之後會寫到.