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