基於nodejs後端微信支付介面
阿新 • • 發佈:2019-01-09
本文不談框架,不談程式碼組織結構,只談怎麼實現,
1,微信移動端支付流程如下:
這個流程可以微信app支付文件找到,最重要的就是統一下單這個介面,可以簡化一下這個介面,簡化後的流程如下:
app給後端傳:金額total_fee,32位的商戶訂單號out_trade_no,支付成功後的回撥地址notify_url 這最基本的3個引數,後端通過微信的統一下單介面https://api.mch.weixin.qq.com/pay/unifiedorder 生成一些引數,在返回給app端,app根據這些引數再加上微信授權,調起微信支付,支付成功後返回到商家app,微信後臺自動檢測是否支出成功,成功後呼叫app傳給微信後端的回撥地址notify_url介面 ,app後端在回撥地址的介面中處理什麼資料庫改寫操作,發訊息等等的動作。
nodejs需要的一些包:
"dependencies": {
"crypto": "^1.0.1",
"express": "^4.16.3",
"request": "^2.85.0",
"xmlreader": "^0.2.3"
}
xmlreader處理xml的工具包,crypto資料加密包
2,工具類util.js
var xmlreader = require("xmlreader"); var fs = require("fs"); 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, 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, 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(); }, //簽名加密演算法,第二次的簽名 paysignjsapifinal: function (appid,mch_id,prepayid,noncestr,timestamp,mchkey) { var ret = { appid: appid, partnerid: mch_id, prepayid: prepayid, package: 'Sign=WXPay', noncestr: noncestr, timestamp: timestamp, }; console.log('retretret==', ret); var string = raw(ret); var key = mchkey; string = string + '&key=' + key; console.log('stringstringstring=', string); var crypto = require('crypto'); return crypto.createHash('md5').update(string, 'utf8').digest('hex').toUpperCase(); }, getXMLNodeValue: function (xml) { // var tmp = xml.split("<"+node_name+">"); // console.log('tmp',tmp); // var _tmp = tmp[1].split("</"+node_name+">"); // console.log('_tmp',_tmp); // return _tmp[0]; 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;
3,呼叫app.js
appid,appsecret是微信開放平臺的資料,mchid是微信對應的商戶平臺id,mchkey是商戶平臺陪的安全祕鑰。
var express = require('express'); var request = require('request'); var xmlreader = require("xmlreader"); var fs = require("fs"); var app = express(); var wxpay = require('./util'); var appid = 'wx28f86efd25cc3312'; var appsecret = 'b8687555bf947b1947b62767c448723'; var mchid = '1499403456' var mchkey = '8r435jVd7yA0354nsvkxb4cN3x7Se4322'; var wxurl = 'http://XXXXXXXXX/weixinNotify.action'; app.get('/',(req,res)=>{ //首先拿到前端傳過來的引數 let orderCode = req.query.orderCode; let money = req.query.money; let orderID = req.query.orderID; 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; let notify_url = wxurl; let trade_type = 'APP'; let sign = wxpay.paysignjsapi(appid,body,mch_id,nonce_str,notify_url,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 += "<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 finalsign = wxpay.paysignjsapifinal(appid,mch_id,prepay_id,nonce_str,timestamp,mchkey); res.json({'appId':appid,'partnerId':mchid,'prepayId':prepay_id,'nonceStr':nonce_str,'timeStamp':timestamp,'package':'Sign=WXPay','sign':finalsign}); }); } }); }) app.listen(3000,()=>{ console.log('伺服器啟動了....'); });