前段时间微信发布JS-SDK接口,其中包括了微信支付,然后就勾起了我一个想法,那是不是我可以在微信上做个H5朋友给我转钱啊,后来才觉得这个想法有多煞笔。
好吧,言归正传,我也是从0开发,摸索了很多资料,网上的jrs看球网直播吧_低调看直播体育app软件下载_低调看体育直播详细不详细,我不知道,反正没有我的详细
微信网页支付,ASP.NET开发,往下看吧。
首先我要先说一下我遇到的几个问题
1、修改测试目录失败,mch_id和appid没有关联关系。
2、签名错误。
3、公众号支付签名错误,无法发起该交易。
第一个错误,我无奈了1整天时间,各种百度,谷歌,都没有找到这样的错误,千万别问客服啊,她们只会让你看文档,后来是直接联系的一个微信支付技术人员把appid给他之后就解决了,如果你们也遇到这样的问题可以发邮件给
好,现在开始开发:
第一步:配置js-sdk配置信息
api: 微信JS-SDK说明文档
使用JS-SDK 必须引用微信js文件:
然后 配置config 权限验证:
wx.config({ debug: false, appId: 'wxc94d5d50202f9dcf', // 必填,公众号的唯一标识 timestamp: <%=wxconfig.timestamp%>,//时间戳 nonceStr: "<%=wxconfig.nonceStr%>",//随机字符串 signature: "<%=wxconfig.signature%>", //权限签名 与微信支付签名没有半毛钱关系 jsApiList: [ // 必填,需要使用的JS接口列表 'onMenuShareTimeline', 'onMenuShareAppMessage', 'getNetworkType', 'chooseWXPay' ] });所有的权限验证算吗 为了安全 需要在后台程序实现
这里的算法是用SHA1,字典排序,而微信支付全部用MD5,注意参数的大小写,url是当前请求网页的url 包括参数。#前面的所有。(需要去公众平台绑定安全域名否则会报invalid url domain 的错误)
////// 获取JS-SDK签名包 /// /// public wxHandleModel.wxJSconfig GetTicket(string url) { wxservice.wxSoapClient wxs = new wxservice.wxSoapClient(); wxs.Get_access_token(appid); string ticket = wxs.Get_access_ticket(appid, false); //验证算法签名的ticket, wxHandleModel.wxJSconfig wxconfig = new wxHandleModel.wxJSconfig(); wxconfig.appId = appid; wxconfig.nonceStr = GenerateCheckCode(16); //随机字符串 wxconfig.timestamp = ConvertDateTimeInt(DateTime.Now); //时间戳 wxconfig.signature = SHA1("jsapi_ticket=" + ticket + "&noncestr=" + wxconfig.nonceStr + "×tamp=" + wxconfig.timestamp + "&url=" + url); return wxconfig; }
api文档中说的非常的清楚,生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次
数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。
wxservice 是我写的web service用来获取更新ticket的,这是看自己如何写方便,一定要缓存,ticket调取频率非常有限。
常见的错误:
invalid url domain 当前页面所在域名与使用的appid没有绑定
invalid signature 签名错误,可以在wx.error函数中 写一个ajax,更新ticket,刷新当前页,如果还是出现这个错误的,检查签名生成参数。
the permission value is offline verifying 这个错误是因为config没有正确执行,或者是调用的JSAPI没有传入config的jsApiList参数中
function not exist 当前客户端版本不支持该接口,请升级到新版体验,好像是要6.01以上的版本
更多错误 看api吧。
签名写好之后,返回前台JS-sdk所有需要页面加载执行的函数需要写在微信加载事件中,wx.ready(function () { });
document.querySelector('#payOK').onclick = function () { wx.chooseWXPay({ timestamp: <%=wxpayconfig.timestamp%>, // 支付签名时间戳 nonceStr: "<%=wxpayconfig.nonceStr%>", // 支付签名随机串 package: "<%=wxpayconfig.package%>", // 统一支付接口返回的package包 signType: "<%=wxpayconfig.signType%>", // 签名方式,'MD5' paySign: "<%=wxpayconfig.paySign %>", // 支付签名 success: function (res) { if(res.err_msg == "get_brand_wcpay_request:ok" ) { alert("支付成功"); // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。 } } }); };这是微信支付点击支付执行的事件,当然支付签名和package包也要在后台实现
第二步:微信支付参数和签名
如果你没有遇到我上面说的第一个问题的话,那么你应该可以直接在微信支付的开发配置中设置 测试支付目录,ok,下面签名算法
使用微信支付前都是通过 统一下单 接口为当前设置一个
请求参数并不是所有的都需要,如果你JSAPI支付的话那么openid必须有,如果是
protected Hashtable Parameters = new Hashtable(); //请求参数集合 string appid = ConfigurationManager.AppSettings["appid"]; //appid string appkey = ConfigurationManager.AppSettings["appkey"]; //商户密匙 string mchid = ConfigurationManager.AppSettings["mchid"]; //商户号
//设置package订单参数 SetParameter("appid", appid); //公众账号ID SetParameter("body", "gtsw-wxpaytest"); //商品描述 SetParameter("mch_id", mchid); //商户号 SetParameter("nonce_str", wxhand.GenerateCheckCode(16).ToLower()); //随机字符串 SetParameter("notify_url", "http://***/wxpay/paycallback.aspx"); //接收财付通通知的URL SetParameter("openid", openid); //openid SetParameter("out_trade_no", wxhand.ConvertDateTimeInt(DateTime.Now) + wxhand.GenerateCheckCode(8)); //商家订单号 SetParameter("spbill_create_ip", sIp); //用户的公网ip,不是商户服务器IP SetParameter("total_fee", "1"); //商品金额,以分为单位(money * 100).ToString() SetParameter("trade_type", "JSAPI"); //交易类型 //签名,需要除sin以外所有的参数都得参与签名 string sign = wxhand.getSin(Parameters, appkey); SetParameter("sign", sign);//签名 string pkxml = wxhand.getDataXML(Parameters); //发送给微信支付统一下单接口 string urlFormat = "https://api.mch.weixin.qq.com/pay/unifiedorder"; var result = wxhand.GetPage(urlFormat, pkxml); //接收微信返回的xml数据 var res = XDocument.Parse(result);
////// 设置发送数据包参数值 /// /// /// public void SetParameter(string parameter, string parameterValue) { if (parameter != null && parameter != "") { if (Parameters.Contains(parameter)) { Parameters.Remove(parameter); } Parameters.Add(parameter, parameterValue); } }
sign是获取prepay_id的签名,参与签名的参数是:除了sign以外的所有参数。(!!!!!!!!MD5加密的结果要大写啊!!!!!!)
appkey是拼接在字符串的最后面 &key=appkey
////// 获取签名 /// ///sin签名 public string getSin(Hashtable ParametersTosin,string appkey) { StringBuilder sb = new StringBuilder(); ArrayList akeys = new ArrayList(ParametersTosin.Keys); akeys.Sort(); foreach (string k in akeys) { string v = (string)ParametersTosin[k]; if (null != v && "".CompareTo(v) != 0 && "sign".CompareTo(k) != 0 && "key".CompareTo(k) != 0) { sb.Append(k + "=" + v + "&"); } } sb.Append("key=" + appkey); string sign = MD5(sb.ToString()).ToUpper(); return sign; }
拿到最重要的prepay_id了,最后的支付签名需要用到它。
if (res.Element("xml").Element("return_code").Value == "SUCCESS") { //下单成功返回 string repayId = res.Element("xml").Element("prepay_id").Value; wxpayconfig = new wxHandleModel.wxPayconfig(); wxpayconfig = wxhand.GetwxPay(repayId); } else { //下单失败返回 wxpayconfig = new wxHandleModel.wxPayconfig(); if (res.Element("xml").Element("return_msg").Value.Contains("openid")) { //如果错误信息为无效的openid,跳转到授权页面重新授权。 Response.Redirect("https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxc94d5d50202f9dcf&redirect_uri=" + oauthurl + "&response_type=code&scope=snsapi_base&state=1#wechat_redirect"); } else { //下单错误信息。 Response.Write("return_code:" + res.Element("xml").Element("return_code").Value + ",return_msg:" + res.Element("xml").Element("return_msg").Value); } }
最后就是要获取微信支付JS中需要的参数了 在 GetwxPay 方法中
////// 获取微信支付JS包 /// /// 预支付ID ///public wxHandleModel.wxPayconfig GetwxPay(string repayId) { wxHandleModel.wxPayconfig wxpayconfig = new wxHandleModel.wxPayconfig(); string package = string.Format("prepay_id={0}", repayId); //package包 wxpayconfig.package = package; wxpayconfig.timestamp = ConvertDateTimeInt(DateTime.Now); //时间戳 string nostr = GenerateCheckCode(16); //随机串 wxpayconfig.nonceStr = nostr; wxpayconfig.signType = "MD5"; //加密方式 string stringA = string.Format(@"appId={0}&nonceStr={1}&package={2}&signType={3}&timeStamp={4}&key={5}" , appid, wxpayconfig.nonceStr, wxpayconfig.package, wxpayconfig.signType, wxpayconfig.timestamp, appkey); wxpayconfig.paySign = MD5(stringA).ToUpper(); //微信支付签名 return wxpayconfig; }
这是最后一步了,也是最终要的一步,随机串和时间戳没什么说的
package 一定要是package=‘wx12212vghdsad’ 这样的形式 , appkey密匙拼接在加密的字符串最后中
参与签名的参数大小写一定要注意,appId 不要写成 appid ,大小写加密出来的字符不同 最后转大写。
还记得请求参数里的回调URLnotify_url 吗,这个也非常重要,
他说:支付完成后,微信会把相关支付结果和用户信息发送给商户,商户需要接收处理,并返回应答。
string postStr = ""; ////// 微信支付回调 /// /// if (Request.HttpMethod.ToLower() == "post") { Stream s = System.Web.HttpContext.Current.Request.InputStream; byte[] b = new byte[s.Length]; s.Read(b, 0, (int)s.Length); postStr = Encoding.UTF8.GetString(b); if (!string.IsNullOrEmpty(postStr)) { //封装请求类 var res = XDocument.Parse(postStr); if (res.Element("xml").Element("return_code").Value == "SUCCESS") { WriteTxt(string.Format(@"商户订单号:{0},订单状态:{1},金额:{2},时间:{3},openid:{4}", res.Element("xml").Element("out_trade_no").Value, res.Element("xml").Element("result_code").Value, res.Element("xml").Element("total_fee").Value, res.Element("xml").Element("time_end").Value, res.Element("xml").Element("openid").Value )); //保存订单信息,并返回微信应答 Response.Write(string.Format(@"")); } else { WriteTxt(res.ToString()); Response.Write(string.Format(@" ", "FAIL", res.Element("xml").Element("return_msg").Value)); } } }
因为是测试,我就把信息保存在了 记事本里,方便查看,一开始我只是接收了微信通知的信息,但是我没有回应 然后记事本里就会增加好多条同一个订单的信息
所以一定要回应微信,一定要以上面代码中 xml的形式,回复之后 你会收到微信支付公众号给你推送的一条消费消息。