版權聲明:本文爲博主原創文章,未經博主容許不得轉載。javascript
目前微信官方的微信支付demo沒有node版本,這幾天一直折騰微信支付,當作筆記記錄下來;
參考資料微信支付官方文檔php
微信支付的簽名採用MD5加密,下面微信支付的簽名算法,及統一下單:
首先先創建一個wechatPay.js 文件(在該文件中包括簽名算法,統一下單等)前端
/** ** 引入依賴包 **/ var config = require('../config'); var request = require("request"); var moment = require('moment'), _ = require('underscore'), https = require('https'), fs = require('fs'), URL = require('url'), CryptoJS = require("crypto-js"), jsontoxml = require('jsontoxml'), xml2js = require('xml2js'); var crypto = require('crypto'); /** ** 簽名算法 **/ var generateSign = exports.genrateSign = function(obj) { var tmpObj = {}; // 取非空的key _.each(obj, function(value, key){ if(value) { tmpObj[key] = value; } }); var keys = _.keys(tmpObj); // key 字典排序 keys = keys.sort(); var tmpArr = []; _.each(keys, function(key) { tmpArr.push(key + "=" + tmpObj[key]) }) tmpArr.push("key=" + config.wxmcn.mcnsecret); // //key爲在微信商戶平臺(pay.weixin.qq.com)-->帳戶設置-->API安全-->密鑰設置 var tmpStr = tmpArr.join('&'); // 拼接字符串 var sign = crypto.createHash('md5').update(tmpStr, 'utf8').digest('hex'); return sign.toUpperCase(); } //統一下單,獲取code_url後期生成二維碼 var paysign = exports.paysign = function(params,callback) { if(_.isEmpty(params)) { callback('參數不能爲空'); } var currentTime = moment().valueOf().toString(); var nonce_str = [ config.wxmcn.mcnid, currentTime ].join(''); // 隨機字符串 var mch_billno = [ config.wxmcn.mcnid, moment().format("YYYYMMDD"), moment().unix() ].join(''); // 訂單號 var ret = { appid: config.H5.appid, body: params.body, // 商品描述 attach: params.attach, // 用戶的身份intid mch_id: config.wxmcn.mcnid, // 商戶號 nonce_str: nonce_str, // 隨機字符串 notify_url:params.notify_url, // 通知地址 out_trade_no:mch_billno, // 商戶訂單號 spbill_create_ip:params.spbill_create_ip, // 終端ip total_fee:params.total_fee, // 標價金額 trade_type:params.trade_type // 交易類型 }; if(!_.isEmpty(params.openid)){ _.extend(ret,{openid: params.openid}); } var sign = generateSign(ret); _.extend(ret,{sign: sign}); var body = jsontoxml(ret); body = '<xml>' + body + '</xml>'; request({ url:'https://api.mch.weixin.qq.com/pay/unifiedorder', method: 'POST', body: body },function (err, response, body) { if (!err && response.statusCode == 200) { // xml2js將返回xml 轉換成json,可是後面都是都數組 xml2js.parseString(body, function(err, json) { if (err) { callback(new Error("解析xml報錯")); } else { var result = formMessage(json.xml); // 轉換成正常的json 數據 if(result.return_code === 'SUCCESS' && result.result_code === 'SUCCESS') { callback(null,result); }else { callback(new Error('wechat err')) } } }) } }); }; // 將xml2js 轉換成json數據進一步轉換 var formMessage = function(result) { var message = {}; if (typeof result === 'object') { var keys = Object.keys(result); for (var i = 0; i < keys.length; i++) { var item = result[keys[i]]; var key = keys[i]; if (!(item instanceof Array) || item.length === 0) { continue; } if (item.length === 1) { var val = item[0]; if (typeof val === 'object') { message[key] = formMessage(val); } else { message[key] = (val || '').trim(); } } else { message[key] = []; for (var j = 0, k = item.length; j < k; j++) { message[key].push(formMessage(itemp[j])); } } } } return message; }
本次開發用的express框架,建立一個wxpayRouter.js(包括獲取微信支付的二維碼等)java
/* ** 引入依賴 */ var express = require('express'); var wxPayRouter = express.Router(); var mongoose = require('mongoose'), ObjectId = mongoose.Schema.Types.ObjectId; var wechatPay = require('./wechatpay') var URL = require('url'), async = require('async'), _ = require('underscore'), qr = require('qr-image'), jsontoxml = require('jsontoxml'), moment = require('moment'); wxPayRouter.get('/order',function(req, res, next){ var params = URL.parse(req.url, true); var queryParams = req.query; total_fee = queryParams.total_fee; // 前端金額 var status = 400, errmsg = ""; if(_.isEmpty(total_fee)) { errmsg = 'total_fee is empty'; } if(errmsg){ return res.end({status: status, msg: errmsg}); } async.auto({ getCodeUrl: function(callback) { var condition = {body: '訂單名稱',attach:'附加信息'}; // attach 會在支付成功的後的原封不動的返回 if(!_.isEmpty(total_fee)) { _.extend(condition, {total_fee: total_fee}); } _.extend(condition, {spbill_create_ip: tools.getLocalIP(),trade_type: 'NATIVE'}); // notify_url 爲微信回調的地址,將支付成功的信息以數據流的形式返回 _.extend(condition,{notify_url: 'http://49727c15.ngrok.io/wxpay/orderpay'}); wechatPay.paysign(condition, function(err, result){ if(err) { return callback(new Error('connect wechat service is fail')); } callback(null,result ); }); } }, function(err, results) { if(err) { return res.end({status: status, msg: err.message}); } var data = results.getCodeUrl; if(_.isEmpty(data)){ status = 404; }else{ status = 200; } res.end({status: status, data: data}); }) }); module.exports = wxPayRouter;
後臺微信的支付接口已經完成,前端調用order接口同時須要將支付金額一併傳遞過來;而後後臺返回相關信息,code_url經過第三方工具生成二維碼,用戶掃碼便可完成支付。node