316
微信
微信小程序教程 第二十七篇 微信小程序支付
微信小程序支付
接入微信支付有三种方式:JSAPI,JSSDK,小程序,而小程序的微信支付,官方这次了一次升级优化,对接开发起来相比更加简易,详情可见官方文档(https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3&index=1)
官方给出的小程序支付交互流程图如下,其实也比较清晰描述了整个过程
宏记(微信号:hongji8410)为了验证这一过程,特地去实操了一下,现整理了下整个过程如下:
首先要准备几个东西
小程序APPID(appid)
商户号(mchid)
商家设置的密钥(key)
在配置小程序时的密钥(secret)
其次,小程序整个支付流程是分为小程序端调用与服务端处理两大块的,其中服务端处理是要与微信服务端进行多次交互处理的。
即 小程序->服务端——>微信服务端->服务端->小程序
签名参数sign主要有两个用处,一个是向微信服务端请求预支付时需要用到这个参数,而另一个是返回小程序端调用确认支付里需要用到,而签名的生成都是通过MD5加密appid+openid/prepay_id等参数而成
最后分步讲解下具体过程
1. 小程序发起
success:function(res){
if (res.code) {
//这里得到jscode即可传到后台进行处理
url:'https://www.voopAPI/getData?js_code='+res.code
data: {},
method: 'GET',
success: function(res){
//后台处理预支付成功,在这就能得到paySign等确认支付需要的参数
}
})
};
};
});
2. 服务端处理
public string GetSessionKeyOpenId(string appid, string secret, string js_code)
{
var url = string.Format("https://api.weixin.qq.com/sns/jscode2session?appid=&secret=&js_code=&grant_type=authorization_code", appid, secret, js_code);
var request = WebRequest.Create(url) as HttpWebRequest;
var response = request.GetResponse();
var respStream = response.GetResponseStream();
var res = string.Empty;
using (var reader = new StreamReader(respStream, Encoding.UTF8))
{
res = reader.ReadToEnd();
}
return res;
}
返回数据
{\”session_key\”:\”a6Td9fWKZx8LkPFCsGA==\”,\”expires_in\”:7200,\”openid\”:\”oujEK0QoA0wI_DDyE5660\”}
其次根据openid,appid,mch_id等参数封装成一个字符串后用MD5加密后向微信服务器统一下单
paramter.AppId = shopinfo.AppId;
paramter.Body = shopinfo.ShopName + "-" + orderpool.OrderPoolCode;
paramter.MchId = shopinfo.MchId;
paramter.Notify_Url = shopinfo.Notify_Url;
paramter.Out_Trade_No = orderpool.OrderPoolCode;
paramter.Spbill_Create_Ip = "127.0.0.1";
paramter.Total_Fee = "1";//(orderpool.NetAmt).ToString(); 暂时1分,用于测试
paramter.Trade_Type = shopinfo.Trade_type;
paramter.Key = shopinfo.Key;
MD5加密得出签名sign
public string GetOrderUnifiedParam(string openid, WXPayParameters param)
{
//参与统一下单签名的参数,除最后的key外,已经按参数名ASCII码从小到大排序
var unifiedorderSignParam = string.Format("appid=&body=&mch_id=&nonce_str=¬ify_url=&openid=&out_trade_no=&spbill_create_ip=&total_fee=&trade_type=&key="
, param.AppId, param.Body, param.MchId, param.Nonce, param.Notify_Url, openid, param.Out_Trade_No, param.Spbill_Create_Ip, param.Total_Fee, param.Trade_Type, param.Key);
//MD5
var unifiedorderSign = GetMD5(unifiedorderSignParam).ToUpper();
//构造统一下单的请求参数
var requestParam = string.Format(@"
", param.AppId, param.Body, param.MchId, param.Nonce, param.Notify_Url, openid, param.Out_Trade_No, param.Spbill_Create_Ip, param.Total_Fee, param.Trade_Type, unifiedorderSign);
return requestParam;
}
将要MD5的字符串
appid=w362e8457f1ca&body=中国特馆-O2017041200015&mch_id=14107872&nonce_str=819F462C255C424244317¬ify_url=https://yourdomain.com/notifyurl&openid=oujEK0QoAI_DDyE5660&out_trade_no=O20170015&spbill_create_ip=127.0.0.1&total_fee=1&trade_type=JSAPI&key=4537751044EE2113393A
MD5后的签名
DFWGFGF81D73DBA86C645D8A3
签名规则注意事项(must)
参数名ASCII码从小到大排序(字典序);
如果参数的值为空不参与签名;
参数名区分大小写;
验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
微信接口可能增加字段,验证签名时必须支持增加的扩展字段
var RespayXML = WXHandleBll.DoPost(param, "https://api.mch.weixin.qq.com/pay/unifiedorder");
发送的XML样式
\r\n w3e843377f9a \r\n 中国馆-O2017041200015\r\n 1445576552 \r\n 819F465763A252422644317\r\n https://voopaip.com/notifyurl\r\noujEK0Q3oAuwI_DDyE5660\r\n O2017200015\r\n 127.0.0.1\r\n 1\r\n JSAPI\r\n A5381D73DBA86D3DC645D8A3\r\n \r\n
最后,根据统一下单请求返回的参数prepay_id再加上appid等参数封装成一个字符串后用MD5再得出一个签名参数,并且处理其它参数后全部返回小程序端所需要的参数
//3.统一下单后拿到的xml结果
var payRes = XDocument.Parse(RespayXML);
var ResXML = payRes.Element("xml");
//序列化相应参数返回给小程序
var res = WXHandleBll.GetPayRequestParam(ResXML, paramter.AppId, paramter.Key);
public WXPayRequesEntity GetPayRequestParam(XElement root, string appid, string key)
{
//当return_code 和result_code都为SUCCESS时才有我们要的prepay_id
if (root.Element("return_code").Value == "SUCCESS" && root.Element("result_code").Value == "SUCCESS")
{
var package = "prepay_id=" + root.Element("prepay_id").Value;
var nonceStr = GetNoncestr();
var signType = "MD5";
var timeStamp = Convert.ToInt64((DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds).ToString();
var paySignParam = string.Format("appId=&nonceStr=&package=&signType=&timeStamp=&key=",
appid, nonceStr, package, signType, timeStamp, key);
var paySign = GetMD5(paySignParam).ToUpper();
{
package = package,
nonceStr = nonceStr,
paySign = paySign,
signType = signType,
timeStamp = timeStamp
};
return payEntity;
}
}
返回XML样式
timeStamp: res.data.Body.Data.timeStamp,
nonceStr: res.data.Body.Data.nonceStr,
package: res.data.Body.Data.package,
signType: 'MD5',
paySign: res.data.Body.Data.paySign,
success: function (res) {
//确认成功
}
});
收集的一些支付坑,方便遇到问题可供查阅
2.签名操作,一定是要配合appId,appid商户号KEY是否正确,参与签名的字符串是否按照要求排序,是否是UTF8格式(实在不行可重置一下),在具体签名方法说明中,可以看出key是在签名参数按照ASCII大小排序完再拼接上去的,
3.返回错误说total_fee参数为空,如果total_fee参数不为空,可能是package格式不对应该为”prepay_id=”+prepay_id,统一下单接口是xml(这个不只是小程序,公众号也是),返回值也是xml格式需要自己获取prepay_id,
4.签名算法要带上key,最后要转换成大些
5.微信支付的sign算法也要带上appid(这个不科学,深坑)
6.签名算法一定不要用json拼接key
7.签名MD5加密,网上有些算法是错误的,自己写完还需要在线MD5加密工具进行校验(我采坑一下午,怎么看我写的怎么对,就是出不来,原因就是MD5工具使用错误,坑爹- - )
8.统一下单签名appid,wx.requestPayment签名appId(大小写必须区分,真是找瞎我钛合金狗眼- - )
9.wx.requestPayment中package参数必须是package:”prepay_id=wx21**“,不然,会出现调用支付JSAPI缺少appid/total_fee
10.total_fee为分,并且是int
11.生成随机数和时间戳一定要保证签名与上传参数一致
13.wx.requestPayment生成签名有appId,请求的时候没有appId
最后更新:2017-10-08 02:11:51