微信小程序中使用JSAPI支付

Posted miao_zz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信小程序中使用JSAPI支付相关的知识,希望对你有一定的参考价值。

微信小程序中使用JSAPI支付

在微信小程序中使用微信支付api【wx.requestPayment】需要传递以下字段

resp数据是通过后台调取腾讯提供的一些接口获取的

uni.requestPayment(
		provider: 'wxpay',
		timeStamp: resp.timeStamp, //时间戳,从 1970 年 1 月 1 日 00:00:00 至今的秒数,即当前的时间
		nonceStr: resp.nonceStr, //随机字符串,长度为32个字符以下
		package: 'prepay_id=' + resp.prepay_id, //统一下单接口返回的 prepay_id 参数值
		signType: 'RSA', //签名算法
		paySign: resp.paySign, //签名
		success: res => ,
		fail: function(err) 
);

如何获取支付所需要的值

1.首先需要前端调起微信的登录api【wx.login】获取code值

//获取微信code
uni.login(
	provider: 'weixin',
	success: loginRes => 
			console.log('[loginRes]', loginRes.code);
	
)

功能描述:
调用接口获取登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户在当前小程序的唯一标识(openid)、微信开放平台帐号下的唯一标识(unionid,若当前小程序已绑定到微信开放平台帐号)及本次登录的会话密钥(session_key)等。用户数据的加解密通讯需要依赖会话密钥完成。

2.把code值传递给服务端,让服务端调用腾讯的auth.code2Session 接口【GET https://api.weixin.qq.com/sns/jscode2session】(具体请求参数请参考官方文档

服务端调起【code2Session】的目的:换取
用户唯一标识 OpenID ,
用户在微信开放平台帐号下的唯一标识UnionID(若当前小程序已绑定到微信开放平台帐号) ,
会话密钥 session_key。

3.服务端获取了Openid后,就可以通过JSAPI下单接口获取到发起支付的必要参数prepay_id,然后使用微信支付提供的小程序方法调起小程序支付。【https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi】(具体请求参数请参考官方文档
通过这个接口获取prepay_id【预支付交易会话标识】

除了prepay_id这个必要字段,其他参数如何获取请参考官方文档

.Net后台实现微信APP支付

上一节分享了微信小程序支付的后台,这一节来分享一下微信APP支付的后台。微信APP支付和微信小程序差别不大,微信APP支付后台不需要微信登录凭证、后台下单时交易类型(trade_type)不再是"JSAPI",而是“APP”、商户后台传递给支付端的下单参数也有所不同。由于微信小程序支付和APP支付使用的APPID不同,索性直接写了两套支付,不再在代码里区分究竟该使用小程序支付的配置参数还是APP支付的参数。

官方是这样介绍的


具体实现:

在WePay文件夹下新建AppPay文件夹(微信支付的公共类在上一节),用于存放微信APP支付用到的类,新建AppPayConfig类

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Web.Configuration;
 7 
 8 namespace App.Pay.WePay.XcxPay
 9 {
10     public class XcxPayConfig : WePayConfig
11     {
12         //=======【基本信息设置】=====================================
13         /* 微信公众号信息配置
14         * APPID:绑定支付的APPID(必须配置)
15         * MCHID:商户号(必须配置)
16         * KEY:商户支付密钥,参考开户邮件设置(必须配置)
17         * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置)
18         */
19         /// 小程序支付
20         public static string APPID = WebConfigurationManager.AppSettings["XcxAppID"].ToString();
21         public static string MCHID = WebConfigurationManager.AppSettings["XcxMchID"].ToString();
22         public static string KEY = WebConfigurationManager.AppSettings["XcxKey"].ToString();
23         public static string APPSECRET = WebConfigurationManager.AppSettings["XcxAppSecret"].ToString();
24 
25         //=======【证书路径设置】===================================== 
26         /* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要)
27         */
28         public const string SSLCERT_PATH = "cert/apiclient_cert.p12";
29         public const string SSLCERT_PASSWORD = "1233410002";
30 
31         //=======【支付结果通知url】===================================== 
32         /* 支付结果通知回调url,用于商户接收支付结果
33         */
34         public static string NOTIFY_URL = WebConfigurationManager.AppSettings["XcxNotifyUrl"].ToString();
35 
36         // log记录
37         public static string LogPath = WebConfigurationManager.AppSettings["XcxLog"].ToString();
38     }
39 }
View Code

新建AppPayHttpService类

  1 using System;
  2 using System.Collections.Generic;
  3 using System.IO;
  4 using System.Linq;
  5 using System.Net;
  6 using System.Net.Security;
  7 using System.Security.Cryptography.X509Certificates;
  8 using System.Text;
  9 using System.Threading.Tasks;
 10 using System.Web;
 11 
 12 namespace App.Pay.WePay.AppPay
 13 {
 14     public class AppPayHttpService
 15     {
 16         private static Log Log = new Log(AppPayConfig.LogPath);
 17 
 18         public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
 19         {
 20             //直接确认,否则打不开    
 21             return true;
 22         }
 23 
 24         public static string Post(string xml, string url, bool isUseCert, int timeout)
 25         {
 26             System.GC.Collect();//垃圾回收,回收没有正常关闭的http连接
 27 
 28             string result = "";//返回结果
 29 
 30             HttpWebRequest request = null;
 31             HttpWebResponse response = null;
 32             Stream reqStream = null;
 33 
 34             try
 35             {
 36                 //设置最大连接数
 37                 ServicePointManager.DefaultConnectionLimit = 200;
 38                 //设置https验证方式
 39                 if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
 40                 {
 41                     ServicePointManager.ServerCertificateValidationCallback =
 42                             new RemoteCertificateValidationCallback(CheckValidationResult);
 43                 }
 44 
 45                 /***************************************************************
 46                 * 下面设置HttpWebRequest的相关属性
 47                 * ************************************************************/
 48                 request = (HttpWebRequest)WebRequest.Create(url);
 49 
 50                 request.Method = "POST";
 51                 request.Timeout = timeout * 1000;
 52 
 53                 //设置代理服务器
 54                 //WebProxy proxy = new WebProxy();                          //定义一个网关对象
 55                 //proxy.Address = new Uri(WxPayConfig.PROXY_URL);              //网关服务器端口:端口
 56                 //request.Proxy = proxy;
 57 
 58                 //设置POST的数据类型和长度
 59                 request.ContentType = "text/xml";
 60                 byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
 61                 request.ContentLength = data.Length;
 62 
 63                 //是否使用证书
 64                 if (isUseCert)
 65                 {
 66                     string path = HttpContext.Current.Request.PhysicalApplicationPath;
 67                     X509Certificate2 cert = new X509Certificate2(path + AppPayConfig.SSLCERT_PATH, AppPayConfig.SSLCERT_PASSWORD);
 68                     request.ClientCertificates.Add(cert);
 69                     //Log.Debug("WxPayApi", "PostXml used cert");
 70                 }
 71 
 72                 //往服务器写入数据
 73                 reqStream = request.GetRequestStream();
 74                 reqStream.Write(data, 0, data.Length);
 75                 reqStream.Close();
 76 
 77                 //获取服务端返回
 78                 response = (HttpWebResponse)request.GetResponse();
 79 
 80                 //获取服务端返回数据
 81                 StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
 82                 result = sr.ReadToEnd().Trim();
 83                 sr.Close();
 84             }
 85             catch (System.Threading.ThreadAbortException e)
 86             {
 87                 Log.Error("HttpService", "Thread - caught ThreadAbortException - resetting.");
 88                 Log.Error("Exception message: {0}", e.Message);
 89                 System.Threading.Thread.ResetAbort();
 90             }
 91             catch (WebException e)
 92             {
 93                 Log.Error("HttpService", e.ToString());
 94                 if (e.Status == WebExceptionStatus.ProtocolError)
 95                 {
 96                     Log.Error("HttpService", "StatusCode : " + ((HttpWebResponse)e.Response).StatusCode);
 97                     Log.Error("HttpService", "StatusDescription : " + ((HttpWebResponse)e.Response).StatusDescription);
 98                 }
 99                 throw new WePayException(e.ToString());
100             }
101             catch (Exception e)
102             {
103                 Log.Error("HttpService", e.ToString());
104                 throw new WePayException(e.ToString());
105             }
106             finally
107             {
108                 //关闭连接和流
109                 if (response != null)
110                 {
111                     response.Close();
112                 }
113                 if (request != null)
114                 {
115                     request.Abort();
116                 }
117             }
118             return result;
119         }
120 
121         /// <summary>
122         /// 处理http GET请求,返回数据
123         /// </summary>
124         /// <param name="url">请求的url地址</param>
125         /// <returns>http GET成功后返回的数据,失败抛WebException异常</returns>
126         public static string Get(string url)
127         {
128             System.GC.Collect();
129             string result = "";
130 
131             HttpWebRequest request = null;
132             HttpWebResponse response = null;
133 
134             //请求url以获取数据
135             try
136             {
137                 //设置最大连接数
138                 ServicePointManager.DefaultConnectionLimit = 200;
139                 //设置https验证方式
140                 if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
141                 {
142                     ServicePointManager.ServerCertificateValidationCallback =
143                             new RemoteCertificateValidationCallback(CheckValidationResult);
144                 }
145 
146                 /***************************************************************
147                 * 下面设置HttpWebRequest的相关属性
148                 * ************************************************************/
149                 request = (HttpWebRequest)WebRequest.Create(url);
150 
151                 request.Method = "GET";
152 
153                 //设置代理
154                 //WebProxy proxy = new WebProxy();
155                 //proxy.Address = new Uri(WxPayConfig.PROXY_URL);
156                 //request.Proxy = proxy;
157 
158                 //获取服务器返回
159                 response = (HttpWebResponse)request.GetResponse();
160 
161                 //获取HTTP返回数据
162                 StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
163                 result = sr.ReadToEnd().Trim();
164                 sr.Close();
165             }
166             catch (System.Threading.ThreadAbortException e)
167             {
168                 Log.Error("HttpService", "Thread - caught ThreadAbortException - resetting.");
169                 Log.Error("Exception message: {0}", e.Message);
170                 System.Threading.Thread.ResetAbort();
171             }
172             catch (WebException e)
173             {
174                 Log.Error("HttpService", e.ToString());
175                 if (e.Status == WebExceptionStatus.ProtocolError)
176                 {
177                     Log.Error("HttpService", "StatusCode : " + ((HttpWebResponse)e.Response).StatusCode);
178                     Log.Error("HttpService", "StatusDescription : " + ((HttpWebResponse)e.Response).StatusDescription);
179                 }
180                 throw new WePayException(e.ToString());
181             }
182             catch (Exception e)
183             {
184                 Log.Error("HttpService", e.ToString());
185                 throw new WePayException(e.ToString());
186             }
187             finally
188             {
189                 //关闭连接和流
190                 if (response != null)
191                 {
192                     response.Close();
193                 }
194                 if (request != null)
195                 {
196                     request.Abort();
197                 }
198             }
199             return result;
200         }
201     }
202 }
View Code

新建AppPayData类

  1 using LitJson;
  2 using System;
  3 using System.Collections.Generic;
  4 using System.Linq;
  5 using System.Security.Cryptography;
  6 using System.Text;
  7 using System.Threading.Tasks;
  8 using System.Xml;
  9 
 10 namespace App.Pay.WePay.AppPay
 11 {
 12     /// <summary>
 13     /// 微信支付协议接口数据类,所有的API接口通信都依赖这个数据结构,
 14     /// 在调用接口之前先填充各个字段的值,然后进行接口通信,
 15     /// 这样设计的好处是可扩展性强,用户可随意对协议进行更改而不用重新设计数据结构,
 16     /// 还可以随意组合出不同的协议数据包,不用为每个协议设计一个数据包结构
 17     /// </summary>
 18     public class AppPayData
 19     {
 20         private Log Log = new Log(AppPayConfig.LogPath);
 21 
 22         public AppPayData()
 23         {
 24         }
 25 
 26         //采用排序的Dictionary的好处是方便对数据包进行签名,不用再签名之前再做一次排序
 27         private SortedDictionary<string, object> m_values = new SortedDictionary<string, object>();
 28 
 29         /**
 30         * 设置某个字段的值
 31         * @param key 字段名
 32          * @param value 字段值
 33         */
 34         public void SetValue(string key, object value)
 35         {
 36             m_values[key] = value;
 37         }
 38 
 39         /**
 40         * 根据字段名获取某个字段的值
 41         * @param key 字段名
 42          * @return key对应的字段值
 43         */
 44         public object GetValue(string key)
 45         {
 46             object o = null;
 47             m_values.TryGetValue(key, out o);
 48             return o;
 49         }
 50 
 51         /**
 52          * 判断某个字段是否已设置
 53          * @param key 字段名
 54          * @return 若字段key已被设置,则返回true,否则返回false
 55          */
 56         public bool IsSet(string key)
 57         {
 58             object o = null;
 59             m_values.TryGetValue(key, out o);
 60             if (null != o)
 61                 return true;
 62             else
 63                 return false;
 64         }
 65 
 66         /**
 67         * @将Dictionary转成xml
 68         * @return 经转换得到的xml串
 69         * @throws WePayException
 70         **/
 71         public string ToXml()
 72         {
 73             //数据为空时不能转化为xml格式
 74             if (0 == m_values.Count)
 75             {
 76                 Log.Error(this.GetType().ToString(), "WxPayData数据为空!");
 77                 throw new WePayException("WxPayData数据为空!");
 78             }
 79 
 80             string xml = "<xml>";
 81             foreach (KeyValuePair<string, object> pair in m_values)
 82             {
 83                 //字段值不能为null,会影响后续流程
 84                 if (pair.Value == null)
 85                 {
 86                     Log.Error(this.GetType().ToString(), "WxPayData内部含有值为null的字段!");
 87                     throw new WePayException("WxPayData内部含有值为null的字段!");
 88                 }
 89 
 90                 if (pair.Value.GetType() == typeof(int))
 91                 {
 92                     xml += "<" + pair.Key + ">" + pair.Value + "</" + pair.Key + ">";
 93                 }
 94                 else if (pair.Value.GetType() == typeof(string))
 95                 {
 96                     xml += "<" + pair.Key + ">" + "<![CDATA[" + pair.Value + "]]></" + pair.Key + ">";
 97                 }
 98                 else//除了string和int类型不能含有其他数据类型
h5微信支付功能封装

微信小程序支付开发之申请退款

.Net后台实现微信APP支付

微信支付时调用支付jsapi缺少参数appid?

微信小程序中如何接入微信支付?

微信小程序怎么跳转到第三方支付页面