android 微信支付 + node.js 服務端
阿新 • • 發佈:2019-01-10
實現微信支付有很多方式,至於開始菜鳥的我使用app支付,後期考慮安全性問題,只好把統一下單,得到prepay_id之後再次簽名sign全在服務端寫了,廢話不多說,進入操作。
做任何東西,我喜歡瞭解整個流程,然後一步一步做起來,開始看清微信支付業務流程圖
業務流程步驟寫的很清楚。下面一步一步操作:
服務端提供介面,服務端需要拿到訂單號、商品介紹、商品價格(單位是分)
服務端對微信服務端發出統一下單請求
https://api.mch.weixin.qq.com/pay/unifiedorder
xml引數(注意引數名)
<xml> <appid>wx2421b1c4370ec43b</appid> <attach>支付測試</attach> <body>APP支付測試</body> <mch_id>10000100</mch_id> <nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str> <notify_url>http://wxpay.weixin.qq.com/pub_v2/pay/notify.v2.php</notify_url> <out_trade_no>1415659990</out_trade_no> <spbill_create_ip>14.23.150.211</spbill_create_ip> <total_fee>1</total_fee> <trade_type>APP</trade_type> <sign>0CB01533B8C1EF103065174F50BCA001</sign> </xml>
請求返回結果是success說明簽名成功
快捷測試方法:
使用https://pay.weixin.qq.com/wiki/tools/signverify/
得到xml引數簽名之後請求看返回結果
推薦一個線上http介面測試工具 http://coolaf.com/
在裡面放入http地址https://api.mch.weixin.qq.com/pay/unifiedorder
post引數放簽名xml引數
返回結果就可以檢測簽名是否成功,成功之後差不多成功了一半
服務端程式碼:weixinpay.js
var request = require('request'); var xml2js = require('xml2js'); function paysign(appid,attach,body,mch_id,nonce_str,notify_url,out_trade_no,spbill_create_ip,total_fee,trade_type) { //統一下單簽名 var ret = { appid: appid, attach: attach, body: body, mch_id: mch_id, nonce_str: nonce_str, notify_url:notify_url, out_trade_no:out_trade_no, spbill_create_ip:spbill_create_ip, total_fee:total_fee, trade_type:trade_type }; var string = raw(ret); var key = '微信商戶金鑰'; string = string + '&key='+key; //key為在微信商戶平臺(pay.weixin.qq.com)-->賬戶設定-->API安全-->金鑰設定 var crypto = require('crypto'); console.log("簽名"); console.log(crypto.createHash('md5').update(string,'utf8').digest('hex').toUpperCase()); return crypto.createHash('md5').update(string,'utf8').digest('hex').toUpperCase(); }; function raw(args) { var keys = Object.keys(args); keys = keys.sort() var newArgs = {}; keys.forEach(function (key) { newArgs[key.toLowerCase()] = args[key]; }); var string = ''; for (var k in newArgs) { string += '&' + k + '=' + newArgs[k]; } string = string.substr(1); console.log(string); return string; }; exports.pay = function (req, res) //微信支付函式 { var url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; var appid = '應用微信中的id'; var mch_id = '商戶號'; var notify_url = 'www.spamao.com'; var out_trade_no = req.query.orderId;<span style="background-color: rgb(255, 255, 102);"><span style="color:#FFFF66;"><span style="background-color: rgb(255, 255, 255);"></span></span></span>//客戶端<span style="background-color: rgb(255, 255, 102);"><span style="color:#FFFF66;"><span style="background-color: rgb(255, 255, 255);"></span></span></span>訂單號 var total_fee = req.query.orderRate;<span style="background-color: rgb(255, 255, 102);"><span style="color:#FFFF66;"><span style="background-color: rgb(255, 255, 255);"></span></span></span>//客戶端<span style="background-color: rgb(255, 255, 102);"><span style="color:#FFFF66;"><span style="background-color: rgb(255, 255, 255);"></span></span></span>商品價格 var attach = 'spamao使用者版app'; var body = req.query.content; //客戶端商品描述 var nonce_str = '隨機32位之內字串'; var formData = "<xml>"; formData += "<appid>"+appid+"</appid>"; //appid formData += "<attach>"+attach+"</attach>"; //附加資料 formData += "<body>"+body+"</body>"; //商品或支付單簡要描述 formData += "<mch_id>"+mch_id+"</mch_id>"; //商戶號 formData += "<nonce_str>"+nonce_str+"</nonce_str>"; //隨機字串,不長於32位 formData += "<notify_url>"+notify_url+"</notify_url>"; //支付成功後微信伺服器通過POST請求通知這個地址 formData += "<out_trade_no>"+out_trade_no+"</out_trade_no>"; //訂單號 formData += "<spbill_create_ip>112.124.60.251</spbill_create_ip>"; //服務端ip formData += "<total_fee>"+total_fee+"</total_fee>"; //金額 formData += "<trade_type>APP</trade_type>"; //型別APP formData += "<sign>" + paysign(appid,attach,body,mch_id,nonce_str,notify_url,out_trade_no,'112.124.60.251',total_fee,'APP') + "</sign>"; formData += "</xml>"; request( { url : url, method : 'POST', body : formData }, function (err, response, body) { if (!err && response.statusCode == 200) { console.log(body); var parser = new xml2js.Parser({ trim:true, explicitArray:false, explicitRoot:false });//解析簽名結果xml轉json parser.parseString(body, function(err, result){ var timeStamp = Date.parse(new Date()) / 1000; var sign = paySignTwo(appid,nonce_str,'Sign=WXPay',mch_id,result['prepay_id'],timeStamp);//得到prepay再次簽名 res.send({result: {'appid':appid, 'mch_id': mch_id, 'prepay_id': result['prepay_id'], 'nonce_str': nonce_str, 'time_stamp':timeStamp, 'package_value':'Sign=WXPay', 'sign': sign}});//返回客戶端資料 }); } } ); } function buildXML(json){ var builder = new xml2js.Builder(); return builder.buildObject(json); }; function paySignTwo(appid,notifystr,packagevalue,mchid,prepayid,timestamp) { //引數名不可改,必須嚴格一模一樣(在此我掉坑一次) var ret = { appid: appid, noncestr: notifystr, package: packagevalue, partnerid: mchid, prepayid: prepayid, timestamp:timestamp }; var string = raw(ret); var key = '商戶金鑰'; string = string + '&key='+key; //key為在微信商戶平臺(pay.weixin.qq.com)-->賬戶設定-->API安全-->金鑰設定 var crypto = require('crypto'); console.log("簽名"); console.log(crypto.createHash('md5').update(string,'utf8').digest('hex').toUpperCase()); return crypto.createHash('md5').update(string,'utf8').digest('hex').toUpperCase(); };
再次簽名引數名:
剩下就是客戶端的事了,短短几行程式碼調起微信支付介面請求。
req = new PayReq(); req.appId = weixinOrder.getString("appid"); req.partnerId = weixinOrder.getString("mch_id"); req.prepayId = weixinOrder.getString("prepay_id"); req.nonceStr = weixinOrder.getString("nonce_str"); req.timeStamp = weixinOrder.getString("time_stamp"); req.packageValue = weixinOrder.getString("package_value"); req.sign = weixinOrder.getString("sign"); Log.i("sign-----jieguo", weixinOrder.getString("sign")); Toast.makeText(WorkPay.this, "正常調起支付", Toast.LENGTH_SHORT).show(); // 在支付之前,如果應用沒有註冊到微信,應該先呼叫IWXMsg.registerApp將應用註冊到微信 api.registerApp(Constants.APP_ID); api.sendReq(req);
manifest需要配置:
<activity android:name="app包名.WorkPay" <!--支付類需加上以下intent-filter內容-->
android:exported="true"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="wxb6ff1aa7f0350ccf"/>
</intent-filter>
</activity>
<activity
android:name="aizhinong.yys.sbm.wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop">
</activity>
提醒:所有引數必須跟微信給的引數名一致(引數個數不能少),(使用微信簽名工具是一定需要分辨測試包簽名還是正式釋出簽名)
如果一切順利,恭喜你接入支付成功。
發這個目的是為了node.js服務端的同胞們多點資源共享