(流程略,若有需要可以留言,另立专题)
获取appid、appsecret、mchid、mchkey
主要是封装金额转换、随机字符串、时间戳、签名加密算法、签名加密二次算法
var xmlreader = require("xmlreader");
var wxpay = {
//把金额转为分
getmoney: function (money) {
return parseFloat(money) * 100;
},
// 随机字符串产生函数
createNonceStr: function () {
return Math.random().toString(36).substr(2, 15);
},
// 时间戳产生函数
createTimeStamp: function () {
return parseInt(new Date().getTime() / 1000) + '';
},
//签名加密算法
paysignjsapi: function (appid, body, mch_id, nonce_str, notify_url, openid, out_trade_no, spbill_create_ip, total_fee, trade_type, mchkey) {
var ret = {
appid: appid,
mch_id: mch_id,
nonce_str: nonce_str,
body: body,
notify_url: notify_url,
openid: openid,
out_trade_no: out_trade_no,
spbill_create_ip: spbill_create_ip,
total_fee: total_fee,
trade_type: trade_type
};
console.log('ret==', ret);
var string = raw(ret);
var key = mchkey;
string = string + '&key=' + key;
console.log('string=', string);
var crypto = require('crypto');
return crypto.createHash('md5').update(string, 'utf8').digest('hex').toUpperCase();
},
// 小程序签名
paysignjsapimini: function (appId, nonceStr, package, signType, timestamp, mchkey) {
var ret = {
appId: appId,
nonceStr: nonceStr,
package: package,
signType: signType,
timeStamp: timestamp,
};
console.log('Miniret==', ret);
var string = raw(ret);
var key = mchkey;
string = string + '&key=' + key;
console.log('Ministring>>>>>>', string);
var crypto = require('crypto');
return crypto.createHash('md5').update(string, 'utf8').digest('hex').toUpperCase();
},
getXMLNodeValue: function (xml) {
xmlreader.read(xml, function (errors, response) {
if (null !== errors) {
console.log(errors)
return;
}
console.log('长度===', response.xml.prepay_id.text().length);
var prepay_id = response.xml.prepay_id.text();
console.log('解析后的prepay_id==', prepay_id);
return prepay_id;
});
}
}
function raw(args) {
var keys = Object.keys(args);
keys = keys.sort()
var newArgs = {};
keys.forEach(function (key) {
newArgs[key] = args[key];
});
var string = '';
for (var k in newArgs) {
string += '&' + k + '=' + newArgs[k];
}
string = string.substr(1);
return string;
}
module.exports = wxpay;
var express = require('express');
var router = express.Router();
var request = require('request');
var xmlreader = require("xmlreader");
var wxpay = require('./util');
var appid = '******'; // 小程序的appid
var appsecret = '******';// 小程序的appSecret
var mchid = '******'; // 微信商户号
var mchkey = '******'; // 微信商户的key 32位
var wxurl = '******'; //通知地址
router.post('/wxpay', function (req, res) {
//首先拿到前端传过来的参数
let orderCode = req.body.orderCode;
let money = req.body.money;
let orderID = req.body.orderID;
let openid = req.body.openid;
console.log('APP传过来的参数是', orderCode + '----' + money + '------' + orderID + '----' + appid + '-----' + appsecret + '-----' + mchid + '-----' + mchkey);
//首先生成签名sign
// appid
let mch_id = mchid;
let nonce_str = wxpay.createNonceStr();
let timestamp = wxpay.createTimeStamp();
let body = '测试微信支付';
let out_trade_no = orderCode;
let total_fee = wxpay.getmoney(money);
let spbill_create_ip = req.connection.remoteAddress; // 支持IPV4和IPV6两种格式的IP地址。调用微信支付API的机器IP
let notify_url = wxurl;
let trade_type = 'JSAPI'; // 'APP';公众号:'JSAPI'或'NATIVE'
let sign = wxpay.paysignjsapi(appid, body, mch_id, nonce_str, notify_url, openid, out_trade_no, spbill_create_ip, total_fee, trade_type, mchkey);
console.log('sign==', sign);
//组装xml数据
var formData = "<xml>";
formData += "<appid>" + appid + "</appid>"; //appid
formData += "<body><![CDATA[" + "测试微信支付" + "]]></body>";
formData += "<mch_id>" + mch_id + "</mch_id>"; //商户号
formData += "<nonce_str>" + nonce_str + "</nonce_str>"; //随机字符串,不长于32位。
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>";
console.log('formData===', formData);
var url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
request({ url: url, method: 'POST', body: formData }, function (err, response, body) {
if (!err && response.statusCode == 200) {
console.log(body);
xmlreader.read(body.toString("utf-8"), function (errors, response) {
if (null !== errors) {
console.log(errors)
return;
}
console.log('长度===', response.xml.prepay_id.text().length);
var prepay_id = response.xml.prepay_id.text();
console.log('解析后的prepay_id==', prepay_id);
//将预支付订单和其他信息一起签名后返回给前端
let package = "prepay_id=" + prepay_id;
let signType = "MD5";
let minisign = wxpay.paysignjsapimini(appid, nonce_str, package, signType, timestamp, mchkey);
res.end(JSON.stringify({ status: '200', data: { 'appId': appid, 'partnerId': mchid, 'prepayId': prepay_id, 'nonceStr': nonce_str, 'timeStamp': timestamp, 'package': 'Sign=WXPay','paySign': minisign } }));
});
}
});
})
//微信获取sessicon
router.post('/jscode2session', function (req, res) {
let APPID = appid;
let SECRET = appsecret;
let CODE = req.body.code;
let _res = res;
let url = 'https://api.weixin.qq.com/sns/jscode2session?appid=' + APPID + '&secret=' + SECRET + '&js_code=' + CODE + '&grant_type=authorization_code'
request({ url: url, method: 'GET' }, function (err, res, body) {
body = JSON.parse(body)
_res.json(body);
// _res.end(JSON.stringify({ "openid": body.openid, "session_key": body.session_key }));
})
})
module.exports = router;
var wxapiRouter = require('./routes/wxapi');
*
*
*
app.use('/wxapi', wxapiRouter);
login.js
function json2Form(json) {
var str = [];
for (var p in json) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(json[p]));
}
return str.join("&");
}
Page({
/**
* 页面的初始数据
*/
data: {},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
this.login();
},
login: function() {
wx.login({
success: res => {
let that = this;
let data = {};
data.code = res.code;
let url = "https://******/wxapi/jscode2session";
wx.request({
method: 'POST',
url: url,
data: json2Form(data),
header: {
'Content-Type': 'application/x-www-form-urlencoded', // 默认值
},
success: res => {
console.log(res.data.openid)
this.wxapi(res.data.openid);
}
})
}
})
},
wxapi: function(openid) {
let that = this;
let data = {};
data.openid = openid;
data.orderCode = "20150909125346"; // 订单号
data.money = "0.01";
data.orderID = "21"; // 订单id
let url = "https://******/wxapi/wxpay";
wx.request({
method: 'POST',
url: url,
data: json2Form(data),
header: {
'Content-Type': 'application/x-www-form-urlencoded', // 默认值
},
success: function(res) {
let data = res.data.data;
console.log(res.data.data);
wx.requestPayment({
timeStamp: data.timeStamp,
nonceStr: data.nonceStr,
// package: data.package,
package: 'prepay_id=' + data.prepayId,
signType: 'MD5',
paySign: data.paySign,
success(res) {
console.log(res)
},
fail(res) {
console.log(res)
}
})
}
})
},
})