//引入統一下單的api var wechatPay = require('./module/wechatPay'); var express = require('express'); var bodyParser = require('body-parser'); var xmlparser = require('express-xml-bodyparser'); var app = new express(); //xmlparser app.use(xmlparser()); app.use(express.static('./public')); //使用中間件body-parser獲取post參數 app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.set('view engine', 'ejs'); app.get('/order', function(req, res) { var openid = ''; var config = { mch_id: '1502539541', wxappid: "wx7bf3787c783116e4", wxpaykey: 'zhongyuantengitying6666666666666' } var pay = new wechatPay(config); pay.createOrder({ openid: openid, notify_url: 'http://118.123.14.36:8000/notifyUrl', //微信支付完成後的回調 out_trade_no: new Date().getTime(), //訂單號 attach: '名稱', body: '購買信息', total_fee: '1', // 此處的額度爲分 spbill_create_ip: req.connection.remoteAddress.replace(/::ffff:/, '') }, function(error, responseData) { console.log('11111111'); console.log(responseData); if (error) { console.log(error); } res.json(responseData); /*簽名字段*/ }); }) app.listen(8000, function() { console.log('port 8000 is running!'); });
支付頁面有金額和標題信息html
applibwechatPay.js
/* * @Descrition : wechat 微信支付功能 */ var url = require('url'); var queryString = require('querystring'); var crypto = require('crypto'); var request = require('request'); var xml2jsparseString = require('xml2js').parseString; // wechat 支付類 (使用 es6 的語法) class WechatPay { /* 構造函數 */ constructor(config) { this.config = config; } /** * 獲取微信統一下單參數 */ getUnifiedorderXmlParams(obj) { var body = '<xml> ' + '<appid>' + this.config.wxappid + '</appid> ' + '<attach>' + obj.attach + '</attach> ' + '<body>' + obj.body + '</body> ' + '<mch_id>' + this.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; } /** * 獲取微信統一下單的接口數據 */ getPrepayId(obj) { var that = this; // 生成統一下單接口參數 var UnifiedorderParams = { appid: this.config.wxappid, attach: obj.attach, body: obj.body, mch_id: this.config.mch_id, nonce_str: this.createNonceStr(), notify_url: obj.notify_url, // 微信付款後的回調地址 openid: obj.openid, //改 out_trade_no: obj.out_trade_no, //new Date().getTime(), //訂單號 spbill_create_ip: obj.spbill_create_ip, total_fee: obj.total_fee, // trade_type : 'JSAPI', trade_type: 'NATIVE' // sign : getSign(), }; // 返回 promise 對象 return new Promise(function(resolve, reject) { // 獲取 sign 參數 UnifiedorderParams.sign = that.getSign(UnifiedorderParams); var url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; request.post({ url: url, body: JSON.stringify(that.getUnifiedorderXmlParams(UnifiedorderParams)) }, function(error, response, body) { var prepay_id = ''; if (!error && response.statusCode == 200) { // 微信返回的數據爲 xml 格式, 須要裝換爲 json 數據, 便於使用 xml2jsparseString(body, { async: true }, function(error, result) { if (error) { console.log(error); reject(error); } else { // prepay_id = result.xml.prepay_id[0]; //小程序支付返回這個 console.log(result); var code_url = result.xml.code_url[0]; resolve(code_url); } }); } else { console.log(body); reject(body); } }); }) } /** * 獲取微信支付的簽名 * @param payParams */ getSign(signParams) { // 按 key 值的ascll 排序 var keys = Object.keys(signParams); keys = keys.sort(); var newArgs = {}; keys.forEach(function(val, key) { if (signParams[val]) { newArgs[val] = signParams[val]; } }) var string = queryString.stringify(newArgs) + '&key=' + this.config.wxpaykey; // 生成簽名 return crypto.createHash('md5').update(queryString.unescape(string), 'utf8').digest("hex").toUpperCase(); } /** * 微信支付的全部參數 * @param req 請求的資源, 獲取必要的數據 * @returns {{appId: string, timeStamp: Number, nonceStr: *, package: string, signType: string, paySign: *}} */ getBrandWCPayParams(obj, callback) { var that = this; var prepay_id_promise = that.getPrepayId(obj); prepay_id_promise.then((prepay_id) => { var prepay_id = prepay_id; var wcPayParams = { "appId": this.config.wxappid, //公衆號名稱,由商戶傳入 "timeStamp": parseInt(new Date().getTime() / 1000).toString(), //時間戳,自1970年以來的秒數 "nonceStr": that.createNonceStr(), //隨機串 // 經過統一下單接口獲取 // "package" : "prepay_id="+prepay_id, //小程序支付用這個 "code_url": prepay_id, "signType": "MD5", //微信簽名方式: }; wcPayParams.paySign = that.getSign(wcPayParams); //微信支付簽名 callback(null, wcPayParams); }, function(error) { callback(error); }); } /** * 獲取隨機的NonceStr */ createNonceStr() { return Math.random().toString(36).substr(2, 15); }; //獲取微信的 AccessToken openid getAccessToken(code, cb) { var that = this; var getAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + this.config.wxappid + "&secret=" + this.config.wxappsecret + "&code=" + code + "&grant_type=authorization_code"; request.post({ url: getAccessTokenUrl }, function(error, response, body) { if (!error && response.statusCode == 200) { if (40029 == body.errcode) { cb(error, body); } else { body = JSON.parse(body); cb(null, body); } } else { cb(error); } }); } /** * 建立訂單 */ createOrder(obj, cb) { this.getBrandWCPayParams(obj, function(error, responseData) { if (error) { cb(error); } else { cb(null, responseData); } }); } } module.exports = WechatPay;
configconfig.default.js
// 微信支付的配置 exports.weixinPayConfig = { mch_id: '1502539541', wxappid: "wx7bf3787c783116e4", wxpaykey: 'zhongyuantengitying6666666666666' } exports.weixinpayBasicParams = { //注意回調地址必須在 微信商戶平臺配置 notify_url: "http://video.apiying.com/weixinpay/weixinpayNotify" }
router.get('/weixinpay/pay', initMiddleware, controller.default.weixinpay.pay);
appcontrollerdefaultweixinpay.js
'use strict'; const Controller = require('egg').Controller; class WeixinpayController extends Controller { async pay() { var d = new Date(); const data = { title: '辣條111', out_trade_no: d.getTime().toString(), price: '0.1' } var code_url = await this.service.weixinpay.doPay(data); //調用方法生成二維碼 var qrImage = await this.service.weixinpay.qrImage(code_url); this.ctx.type = 'image/png'; this.ctx.body = qrImage; } } module.exports = WeixinpayController;
appserviceweixinpay.js
'use strict'; var wechatPay = require('../lib/wechatPay.js'); const qr = require('qr-image'); const Service = require('egg').Service; class WeixinpayService extends Service { async doPay(orderData) { return new Promise((resove) => { var pay = new wechatPay(this.config.weixinPayConfig); var notify_url = this.config.weixinpayBasicParams.notify_url; var out_trade_no = orderData.out_trade_no; var title = orderData.title; var price = orderData.price * 100; var ip = this.ctx.request.ip.replace(/::ffff:/, ''); pay.createOrder({ openid: '', notify_url: notify_url, //微信支付完成後的回調 out_trade_no: out_trade_no, //訂單號 attach: title, body: title, total_fee: price.toString(), // 此處的額度爲分 spbill_create_ip: ip }, function(error, responseData) { console.log(responseData); if (error) { console.log(error); } resove(responseData.code_url) }); }) } async qrImage(url) { var qrimg = qr.image(url, { type: 'png' }); return qrimg; } } module.exports = WeixinpayService;
appviewdefaultconfirm.html
<div class="payment-box "> <div class="payment-body"> <ul class="clearfix payment-list J_paymentList J_linksign-customize"> <li id="weixinPay"><img src="//c1.mifile.cn/f/i/16/pay/weixinpay0701.png" alt="微信支付" style="margin-left: 0;"></li> <li class="J_bank" id="alipay"> <a target="_blank" href="/alipay/pay?id=<%=orderResult._id%>"> <img src="//s01.mifile.cn/i/banklogo/payOnline_zfb.png?ver2015" alt="支付寶" style="margin-left: 0;"></a> </li> </ul> </div> </div>
<div class="modal fade" id="weixinPayModel" tabindex="-1" role="dialog"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">微信支付</h4> </div> <div class="modal-body"> <img class="lcode" src="/weixinpay/pay?id=1242141244" /> <img class="rphone" src="/public/default/image/phone.png" /> </div> </div> </div> </div>
$("#weixinPay").click(function() { $('#weixinPayModel').modal('show'); })
把訂單信息經過微信支付js,轉成url,再把url轉成二維碼git
//異步通知 注意關閉csrf驗證 router.post('/weixinpay/weixinpayNotify', initMiddleware, xmlparseMiddleware, controller.default.weixinpay.weixinpayNotify);
configconfig.default.js
config.security = { csrf: { // 判斷是否須要 ignore 的方法,請求上下文 context 做爲第一個參數 ignore: ctx => { if (ctx.request.url == '/admin/goods/goodsUploadImage' || ctx.request.url == '/admin/goods/goodsUploadPhoto' || ctx.request.url == '/pass/doLogin' || ctx.request.url == '/user/addAddress' || ctx.request.url == '/user/editAddress' || ctx.request.url == '/admin/goods/goodsUploadPhoto' || ctx.request.url == '/weixinpay/weixinpayNotify') { return true; } return false; } } }
appcontrollerdefaultweixinpay.js
//異步通知 async weixinpayNotify(){ let that = this; let data = ''; this.ctx.req.on('data',function(chunk){ data += chunk; }); this.ctx.req.on('end',function(){ xml2js(data,{explicitArray:false}, function (err, json) { console.log(json);//這裏的json即是xml轉爲json的內容 var mySign=that.service.weixinpay.weixinpayNotify(json.xml); console.log(mySign); console.log('-------------'); console.log(json.xml.sign); }); }); }
appserviceweixinpay.js
weixinpayNotify(params) { var pay = new wechatPay(this.config.weixinPayConfig); var notifyObj = params; var signObj = {}; for (var attr in notifyObj) { if (attr != 'sign') { signObj[attr] = notifyObj[attr] } } var sign = pay.getSign(signObj); return sign; }
微信支付後不會自動跳轉es6
5秒鐘判斷一次狀態express
修改支付狀態和訂單狀態爲1(成功)json
支付狀態和訂單狀態爲1(成功),則跳轉到訂單頁面小程序
//檢測訂單是否支付 router.get('/buy/getOrderPayStatus', initMiddleware, userauthMiddleware, controller.default.buy.getOrderPayStatus); router.get(' /user/order', initMiddleware, userauthMiddleware, controller.default.user.order);
appcontrollerdefaultbuy.js
async getOrderPayStatus() { /* 一、獲取訂單號 二、查詢當前訂單的支付狀態 三、若是支付 返回成功 若是沒有支付返回失敗信息 */ var id = this.ctx.request.query.id; if (id) { try { var orderReuslt = await this.ctx.model.Order.find({ "_id": id }); if (orderReuslt && orderReuslt[0].pay_status == 1 && orderReuslt[0].order_status == 1) { this.ctx.body = { success: true, message: '已支付' } } else { this.ctx.body = { success: false, message: '未支付' } } } catch (error) { this.ctx.body = { success: false, message: '未支付' } } } else { this.ctx.body = { success: false, message: '未支付' } } }
appviewdefaultconfirm.html
setInterval(function() { $.get('/buy/getOrderPayStatus?id=<%=id%>', function(response) { console.log(response); if (response.success) { location.href = '/user/order' } }) }, 5000);