NodeJS微信支付分可以为三个部分:
一、前端获取code获取用户Oppenid
二、拿到当前用户支付的请求参数
三、支付成功后的跳转
先说第一步骤吧
1)通过js脚本请求请求微信后台并返回code(JS跳转获取回调当前URL)
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=' + encodeURIComponent(URL) + '&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect
参数说明:
1:appid为公众号的ID
2:encodeURIComponent(URL)为加密当前你在微信后台JS_API配置的安全域名
3. response_type=code,这个没什么好说的就是固定的 response_type=code,详细说明可以查看微信官网的说明
4. scope=snsapi_base,固定这样写就好,详细说明可以查看微信官网的说明
5. state=STATE 固定这样写就好,详细说明可以查看微信官网的说明
6. wechat_redirect 固定这样写就好,详细说明可以查看微信官网的说明
2)通过code获取当前用户信息access_token
方法如下:
$.ajax({
url: '/astokenOpid',
dataType: 'json',
type: 'post',
ContentType: "application/json",
data: {
CODES: wxcodes
},
success: function(data) {
localStorage.setItem('userData', JSON.stringify(data));
},
});
参数说明:
1、/astokenOpid 为当前node后台服务中的一个方法(后面会贴出来)
2、wxcodex 为当前上一步微信返回的code
3、success中的fun为当前返回用户
/astokenOpid方法如下(node后台方法)
request.get({
url: 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRECT&code=' + req.body.CODES + '&grant_type=authorization_code',
form: {}
}, function(error, response, body) {
console.log(body);
if (!error && response.statusCode == 200) {
var userdata = JSON.parse(body);
res.json(userdata);
}
});
3)调取微信原生进行公众号支付
案例如下
/**
* 微信支付
*/
wxpay(wxcodes) {
let _this = this;
$.ajax({
url: '/wxpay',
dataType: 'json',
type: 'post',
ContentType: "application/json",
data: {
CODES: wxcodes,
token: '', // access_token
opid: '', // oppenid
retoken: '', // refresh_token
scope: '',// scope
expin: '',// expires_in
bodyDetail: '',// 支付详情
bodyTitle: '',// 支付标题
Totla_fees: // 支付金额 注:微信支付单位为整形最小值为1 以分为单位
},
success: function(data) {
wxdata.appId = data.appId;
wxdata.timeStamp = data.timeStamp;
wxdata.nonceStr = data.nonceStr;
wxdata.package = data.package;
wxdata.signType = data.signType;
wxdata.paySign = data.paySign;
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', _this.onBridgeReady(data.orderNum), false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', _this.onBridgeReady(data.orderNum));
document.attachEvent('onWeixinJSBridgeReady', _this.onBridgeReady(data.orderNum));
}
} else { _this.onBridgeReady(data.orderNum); }
},
});
};
参数注解:
1、wxdata为全局公用对象;
2、/wxpay 为后台路由接受控制器 支付的func;
3、data参数为当前上一步后台获取oppenid用户信息和当前需要支付的订单金额、详细及标题;
4)支付过程及其成功后回调的页面
/**
* 调取原生支付
*/
onBridgeReady(oderNumber) {
let _this = this;
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": wxdata.appId,
"timeStamp": wxdata.timeStamp,
"nonceStr": wxdata.nonceStr,
"package": wxdata.package,
"signType": wxdata.signType,
"paySign": wxdata.paySign
},
function(res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
prompt.tipMsgBox('支付成功');
} else if (res.err_msg == "get_brand_wcpay_request:cancel") {
prompt.tipMsgBox('支付已取消');
} else if (res.err_msg == "get_brand_wcpay_request:fail") {
prompt.tipMsgBox('支付失败:网络错误,稍后重试');
}
}
);
};
微信支付返回状态码
5)下面的都是node后台版本微信支付签名加支付的代码
路由模块支付
/**
* 获取wxpay
*/
router.post('/wxpay', function(req, res, next) {
let reqs= req.body; // 页面点击支付跳转过来的方法参数
let ress = res;
var ip = req.headers['x-real-ip'] ? req.headers['x-real-ip'] : req.ip.replace(/::ffff:/, ''); //获取当前用户的ID
wxpay.prototype.getAccessToken(reqs.reqTotla, reqs.CODES, ip, reqs.token, reqs.opid, reqs.retoken, reqs.scope, reqs.expin, function(data, orderNumber) {
data.orderNum = orderNumber
ress.json(data);
}, reqs.bodyDetail, reqs.bodyTitle);
});
支付的方法脚本
var url = require('url');
var queryString = require('querystring');
var crypto = require('crypto');
var request = require('request');
var xml2jsparseString = require('xml2js').parseString;
var http = require('http');
var querystring = require('querystring');
var md5 = require('md5');
var cookParser = require('cookie-parser');
var session = require('express-session');
var express = require('express');
var app = express();
var times = new Date().getTime();
var nonce = Math.random();
let ordernumbers = '';
var addData = {
'signature': '', // 签名
'userid': session('id') || '', // 用户ID
'timestamp': times, // 时间戳
'nonce': nonce // 随机数
}
function signature(uid, utoken) {
let id = uid || '';
let token = utoken || '';
var strins = times + '' + nonce + '' + id.toString().toUpperCase() + '' + token.toString().toUpperCase()
var arrayList = strins.split('')
var sortList = arrayList.sort(function(a, b) { return a.localeCompare(b) })
var sortString = sortList.join('')
var md5String = md5(sortString).toString().toUpperCase();
return md5String
}
// 引入项目的配置信息
// var config = require('../config/index.js');
var obj = {
appid: '',// APPID
attach: '', // 可为空attach
body: '',
mch_id: '1327276501', // mch_id 详见微信公众号
nonce_str: '',
notify_url: '/success', // 微信付款后的回调地址
openid: '',
out_trade_no: '', // new Date().getTime(), //订单号
spbill_create_ip: '', //客户端的ip
total_fee: '', //商品的价格, 此处需要注意的是这个价格是以分算的, 那么一般是元, 你需要转换为 RMB 的元 Y
trade_type: 'JSAPI',
}
config = {
wxappid: '',// APPID详见微信公众号
mch_id: '', // mch_id 详见公众号
wxpaykey: '',// 微信的支付key
wxappsecret: '', // 微信secret
WxSSLCERT_PATH: '',// 微信sslcert_path 可为空
WxNOTIFY_URL: '/success', // 成功后回调页面
WxNOTIFY_ERROR_URL: '/error',// 失败后回调页面
WxLOG_LEVENL: '3', // 详见公众号日志模式 Log_levenl
WxToken: ''// 详见公众号token
};
// 支付需要用到的参数
var userInfo = {
access_token: '',
expires_in: '',
refresh_token: '',
openid: '',
scope: '',
};
class WechatPay {
/**
* 获取微信统一下单参数
*/
getUnifiedorderXmlParams(obj) {
var body = '<xml> ' +
'<appid>' + config.wxappid + '</appid> ' +
'<attach>' + obj.attach + '</attach> ' +
'<body>' + obj.body + '</body> ' +
'<mch_id>' + config.mch_id + '</mch_id> ' +
'<nonce_str>' + obj.nonce_str + '</nonce_str> ' +
'<notify_url>' + obj.notify_url + '</notify_url>' +
'<openid>' + obj.openid + '</openid> ' +
'<out_trade_no>' + obj.out_trade_no + '</out_trade_no>' +
'<spbill_create_ip>' + obj.spbill_create_ip + '</spbill_create_ip> ' +
'<total_fee>' + obj.total_fee + '</total_fee> ' +
'<trade_type>' + obj.trade_type + '</trade_type> ' +
'<sign>' + obj.sign + '</sign> ' +
'</xml>';
return body;
}
/**
* 随机数
*/
createNonceStr() {
return Math.random().toString(36).substr(2, 15);
};
/**
* 获取微信的 AccessToken
*/
getAccessToken(total, code, ip, token, opid, retoken, scope, expin, callback, bodyDetail, bodyTitle) {
var that = this;
total = parseFloat(total) * 100;
obj.spbill_create_ip = ip;
obj.total_fee = total;
obj.body = bodyDetail;
obj.attach = bodyTitle;
request.get({
url: "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + config.wxappid + "&secret=" + config.wxappsecret + "&code=" + code + "&grant_type=authorization_code",
form: {}
}, function(error, response, body) {
if (!error && response.statusCode == 200) {
userInfo.access_token = token;
userInfo.expires_in = expin;
userInfo.refresh_token = retoken;
userInfo.openid = opid;
userInfo.scope = scope;
obj.openid = opid;
// 拼接微信的支付的参数
that.getBrandWCPayParams(function(error, responseData, orderNumber) {
console.log(orderNumber);
callback && callback(responseData, orderNumber);
});
}
});
};
}