实现微信支付有很多方式,至于开始菜鸟的我使用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服务端的同胞们多点资源共享