一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術(shù)及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - ASP.NET教程 - 微信公眾平臺支付開發(fā)詳解

微信公眾平臺支付開發(fā)詳解

2020-04-18 14:23stoneniqiu ASP.NET教程

本文主要介紹了微信開發(fā)中公眾號支付的實現(xiàn)方法與步驟。具有很好的參考價值,下面跟著小編一起來看下吧

公眾號支付就是在微信里面的H5頁面喚起微信支付,不用掃碼即可付款的功能。做這個功能首先要明確的就是,只有和商戶號mch_id匹配的appid才能成功支付。商戶號在注冊成功的時候就會將相關(guān)信息發(fā)送到郵箱里面。而喚起支付的一個關(guān)鍵是靠openid拿到統(tǒng)一下單。而openid是和appid一一對應的。也就是說如果你登錄使用的appid不是公眾號的appid,得到的openid就無法喚起公眾號內(nèi)的支付(會出現(xiàn)appid和商戶號不匹配的錯誤)。曾經(jīng)就在這個地方繞了個彎,因為微信的開放平臺可以創(chuàng)建網(wǎng)站應用,也有一個appid和appsecreat,也可以在微信里面一鍵登錄。

業(yè)務流程

下面是微信的官方流程,看似有點復雜,重點就是要拿到統(tǒng)一下單接口返回的json串,其他按照官方demo基本就能正確,下面說一下幾個細節(jié)。

微信公眾平臺支付開發(fā)詳解

創(chuàng)建訂單

在調(diào)用微信公眾號支付之前,首先我們自己要把訂單創(chuàng)建好。比如一個充值的訂單。主要是先確定下金額再進行下一步。

?
1
2
3
4
5
6
7
public JsonResult CreateRecharegOrder(decimal money)
 {
 if (money < (decimal)0.01) return Json(new PaymentResult("充值金額非法!"));
 var user = _workContext.CurrentUser;
 var order = _paymentService.CreateRechargeOrder(user.Id, money);
 return Json(new PaymentResult(true) {OrderId = order.OrderNumber});
 }

調(diào)用統(tǒng)一下單

訂單創(chuàng)建成功之后,頁面跳轉(zhuǎn)到支付頁面,這個時候就是按照官方的流程去拿prepay_id和paySign,微信的demo中提供了一個jsApiPay的對象。但這個對象需要一個page對象初始化。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[LoginValid]
 public ActionResult H5Pay(string orderNumber)
 {
 var user = _workContext.CurrentUser;
 var order = _paymentService.GetOrderByOrderNumber(orderNumber);
 //判斷訂單是否存在
 //訂單是否已經(jīng)支付了
 var openid = user.OpenId;
 var jsApipay = new JsApiPayMvc(this.ControllerContext.HttpContext);
 jsApipay.openid = openid;
 jsApipay.total_fee = (int)order.Amount * 100;
 WxPayData unifiedOrderResult = jsApipay.GetUnifiedOrderResult();
 ViewBag.wxJsApiParam = jsApipay.GetJsApiParameters();//獲取H5調(diào)起JS API參數(shù)
 ViewBag.unifiedOrder = unifiedOrderResult.ToPrintStr();
 ViewBag.OrderNumber = order.OrderNumber;
 return View();
 }

在MVC中我們簡單改一下就可以了。也就是把page對象換成httpContext即可。然后里面的方法就可以直接用了。

JsApiPayMvc:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Runtime.Serialization;
using System.IO;
using System.Text;
using System.Net;
using System.Web.Security;
using LitJson;
namespace WxPayAPI
{
 public class JsApiPayMvc
 {
 /// <summary>
 /// 保存頁面對象,因為要在類的方法中使用Page的Request對象
 /// </summary>
 public HttpContextBase context { get; set; }
 /// <summary>
 /// openid用于調(diào)用統(tǒng)一下單接口
 /// </summary>
 public string openid { get; set; }
 /// <summary>
 /// access_token用于獲取收貨地址js函數(shù)入口參數(shù)
 /// </summary>
 public string access_token { get; set; }
 /// <summary>
 /// 商品金額,用于統(tǒng)一下單
 /// </summary>
 public int total_fee { get; set; }
 /// <summary>
 /// 統(tǒng)一下單接口返回結(jié)果
 /// </summary>
 public WxPayData unifiedOrderResult { get; set; }
 public JsApiPayMvc(HttpContextBase _context)
 {
 context = _context;
 }
 /**
 *
 * 網(wǎng)頁授權(quán)獲取用戶基本信息的全部過程
 * 詳情請參看網(wǎng)頁授權(quán)獲取用戶基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
 * 第一步:利用url跳轉(zhuǎn)獲取code
 * 第二步:利用code去獲取openid和access_token
 *
 */
 public void GetOpenidAndAccessToken(string code)
 {
 if (!string.IsNullOrEmpty(code))
 {
 //獲取code碼,以獲取openid和access_token
 Log.Debug(this.GetType().ToString(), "Get code : " + code);
 GetOpenidAndAccessTokenFromCode(code);
 }
 else
 {
 //構(gòu)造網(wǎng)頁授權(quán)獲取code的URL
 string host = context.Request.Url.Host;
 string path = context.Request.Path;
 string redirect_uri = HttpUtility.UrlEncode("http://" + host + path);
 WxPayData data = new WxPayData();
 data.SetValue("appid", WxPayConfig.APPID);
 data.SetValue("redirect_uri", redirect_uri);
 data.SetValue("response_type", "code");
 data.SetValue("scope", "snsapi_base");
 data.SetValue("state", "STATE" + "#wechat_redirect");
 string url = "https://open.weixin.qq.com/connect/oauth2/authorize?" + data.ToUrl();
 Log.Debug(this.GetType().ToString(), "Will Redirect to URL : " + url);
 try
 {
 //觸發(fā)微信返回code碼
 context.Response.Redirect(url);//Redirect函數(shù)會拋出ThreadAbortException異常,不用處理這個異常
 }
 catch(System.Threading.ThreadAbortException ex)
 {
 }
 }
 }
 /**
 *
 * 通過code換取網(wǎng)頁授權(quán)access_token和openid的返回數(shù)據(jù),正確時返回的JSON數(shù)據(jù)包如下:
 * {
 * "access_token":"ACCESS_TOKEN",
 * "expires_in":7200,
 * "refresh_token":"REFRESH_TOKEN",
 * "openid":"OPENID",
 * "scope":"SCOPE",
 * "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
 * }
 * 其中access_token可用于獲取共享收貨地址
 * openid是微信支付jsapi支付接口統(tǒng)一下單時必須的參數(shù)
 * 更詳細的說明請參考網(wǎng)頁授權(quán)獲取用戶基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
 * @失敗時拋異常WxPayException
 */
 public void GetOpenidAndAccessTokenFromCode(string code)
 {
 try
 {
 //構(gòu)造獲取openid及access_token的url
 WxPayData data = new WxPayData();
 data.SetValue("appid", WxPayConfig.APPID);
 data.SetValue("secret", WxPayConfig.APPSECRET);
 data.SetValue("code", code);
 data.SetValue("grant_type", "authorization_code");
 string url = "https://api.weixin.qq.com/sns/oauth2/access_token?" + data.ToUrl();
 //請求url以獲取數(shù)據(jù)
 string result = HttpService.Get(url);
 Log.Debug(this.GetType().ToString(), "GetOpenidAndAccessTokenFromCode response : " + result);
 //保存access_token,用于收貨地址獲取
 JsonData jd = JsonMapper.ToObject(result);
 access_token = (string)jd["access_token"];
 //獲取用戶openid
 openid = (string)jd["openid"];
 Log.Debug(this.GetType().ToString(), "Get openid : " + openid);
 Log.Debug(this.GetType().ToString(), "Get access_token : " + access_token);
 }
 catch (Exception ex)
 {
 Log.Error(this.GetType().ToString(), ex.ToString());
 throw new WxPayException(ex.ToString());
 }
 }
 /**
 * 調(diào)用統(tǒng)一下單,獲得下單結(jié)果
 * @return 統(tǒng)一下單結(jié)果
 * @失敗時拋異常WxPayException
 */
 public WxPayData GetUnifiedOrderResult()
 {
 //統(tǒng)一下單
 WxPayData data = new WxPayData();
 data.SetValue("body", "test");
 data.SetValue("attach", "test");
 data.SetValue("out_trade_no", WxPayApi.GenerateOutTradeNo());
 data.SetValue("total_fee", total_fee);
 data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));
 data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));
 data.SetValue("goods_tag", "test");
 data.SetValue("trade_type", "JSAPI");
 data.SetValue("openid", openid);
 WxPayData result = WxPayApi.UnifiedOrder(data);
 if (!result.IsSet("appid") || !result.IsSet("prepay_id") || result.GetValue("prepay_id").ToString() == "")
 {
 Log.Error(this.GetType().ToString(), "UnifiedOrder response error!");
 throw new WxPayException("UnifiedOrder response error!");
 }
 unifiedOrderResult = result;
 return result;
 }
 /**
 *
 * 從統(tǒng)一下單成功返回的數(shù)據(jù)中獲取微信瀏覽器調(diào)起jsapi支付所需的參數(shù),
 * 微信瀏覽器調(diào)起JSAPI時的輸入?yún)?shù)格式如下:
 * {
 * "appId" : "wx2421b1c4370ec43b", //公眾號名稱,由商戶傳入
 * "timeStamp":" 1395712654", //時間戳,自1970年以來的秒數(shù)
* "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //隨機串
* "package" : "prepay_id=u802345jgfjsdfgsdg888",
 * "signType" : "MD5", //微信簽名方式:
* "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信簽名
 * }
 * @return string 微信瀏覽器調(diào)起JSAPI時的輸入?yún)?shù),json格式可以直接做參數(shù)用
 * 更詳細的說明請參考網(wǎng)頁端調(diào)起支付API:http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7
 *
 */
 public string GetJsApiParameters()
 {
 Log.Debug(this.GetType().ToString(), "JsApiPay::GetJsApiParam is processing...");
 
 WxPayData jsApiParam = new WxPayData();
 jsApiParam.SetValue("appId", unifiedOrderResult.GetValue("appid"));
 jsApiParam.SetValue("timeStamp", WxPayApi.GenerateTimeStamp());
 jsApiParam.SetValue("nonceStr", WxPayApi.GenerateNonceStr());
 jsApiParam.SetValue("package", "prepay_id=" + unifiedOrderResult.GetValue("prepay_id"));
 jsApiParam.SetValue("signType", "MD5");
 jsApiParam.SetValue("paySign", jsApiParam.MakeSign());
 string parameters = jsApiParam.ToJson();
 Log.Debug(this.GetType().ToString(), "Get jsApiParam : " + parameters);
 return parameters;
 }
 /**
 *
 * 獲取收貨地址js函數(shù)入口參數(shù),詳情請參考收貨地址共享接口:http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_9
 * @return string 共享收貨地址js函數(shù)需要的參數(shù),json格式可以直接做參數(shù)使用
 */
 public string GetEditAddressParameters()
 {
 string parameter = "";
 try
 {
 string host = context.Request.Url.Host;
 string path = context.Request.Path;
 string queryString = context.Request.Url.Query;
 //這個地方要注意,參與簽名的是網(wǎng)頁授權(quán)獲取用戶信息時微信后臺回傳的完整url
 string url = "http://" + host + path + queryString;
 //構(gòu)造需要用SHA1算法加密的數(shù)據(jù)
 WxPayData signData = new WxPayData();
 signData.SetValue("appid",WxPayConfig.APPID);
 signData.SetValue("url", url);
 signData.SetValue("timestamp",WxPayApi.GenerateTimeStamp());
 signData.SetValue("noncestr",WxPayApi.GenerateNonceStr());
 signData.SetValue("accesstoken",access_token);
 string param = signData.ToUrl();
 Log.Debug(this.GetType().ToString(), "SHA1 encrypt param : " + param);
 //SHA1加密
 string addrSign = FormsAuthentication.HashPasswordForStoringInConfigFile(param, "SHA1");
 Log.Debug(this.GetType().ToString(), "SHA1 encrypt result : " + addrSign);
 //獲取收貨地址js函數(shù)入口參數(shù)
 WxPayData afterData = new WxPayData();
 afterData.SetValue("appId",WxPayConfig.APPID);
 afterData.SetValue("scope","jsapi_address");
 afterData.SetValue("signType","sha1");
 afterData.SetValue("addrSign",addrSign);
 afterData.SetValue("timeStamp",signData.GetValue("timestamp"));
 afterData.SetValue("nonceStr",signData.GetValue("noncestr"));
 //轉(zhuǎn)為json格式
 parameter = afterData.ToJson();
 Log.Debug(this.GetType().ToString(), "Get EditAddressParam : " + parameter);
 }
 catch (Exception ex)
 {
 Log.Error(this.GetType().ToString(), ex.ToString());
 throw new WxPayException(ex.ToString());
 }
 return parameter;
 }
 }
}

這個頁面可以在本地調(diào)試,可以比較方便的確認參數(shù)是否ok。

喚起支付

官方頁面的示例如下:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6 但主要的參數(shù)(mark部分)是由后臺生成的,也就是上一個步驟的ViewBag.wxJsApiParam

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function onBridgeReady(){
 WeixinJSBridge.invoke(
 'getBrandWCPayRequest', {
 "appId" "wx2421b1c4370ec43b", //公眾號名稱,由商戶傳入
 "timeStamp"" 1395712654", //時間戳,自1970年以來的秒數(shù)
 "nonceStr" "e61463f8efa94090b1f366cccfbbb444", //隨機串
 "package" "prepay_id=u802345jgfjsdfgsdg888",
 "signType" "MD5", //微信簽名方式:
 "paySign" "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信簽名
 },
 function(res){
 if(res.err_msg == "get_brand_wcpay_request:ok" ) {} // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功后返回 ok,但并不保證它絕對可靠。
 }
 );
}

所以在MVC中要這樣寫:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
@{
 ViewBag.Title = "微信支付";
 Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="page" id="Wxpayment">
 <div class="content">
 <div>訂單詳情:@Html.Raw(ViewBag.unifiedOrder)</div>
 <button id="h5pay" onclick="callpay()">支付</button>
 </div>
 <input type="hidden" value="@ViewBag.OrderNumber" id="ordernum"/>
</div>
<script type="text/javascript">
 //調(diào)用微信JS api 支付
 function jsApiCall() {
 WeixinJSBridge.invoke(
 'getBrandWCPayRequest',
 @Html.Raw(ViewBag.wxJsApiParam),//josn串
 function (res)
 {
 WeixinJSBridge.log(res.err_msg);
 //alert(res.err_code + res.err_desc + res.err_msg);
 if (res.err_msg == "get_brand_wcpay_request:ok") {
 var num = $("#ordernum").val();
 $.post("/payment/WeiXinPaySuccess", { ordernumber: num }, function(data) {
 if (data.IsSuccess === true) {
 alert("支付成功");
 location.href = document.referrer;
 } else {
 }
 });
 }
 if (res.err_msg == 'get_brand_wcpay_request:cancel') {
 $('.button').removeAttr('submitting');
 alert('取消支付');
 }
 }
 );
 }
 function callpay()
 {
 if (typeof WeixinJSBridge == "undefined")
 {
 alert("WeixinJSBridge =");
 if (document.addEventListener)
 {
 document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
 }
 else if (document.attachEvent)
 {
 document.attachEvent('WeixinJSBridgeReady', jsApiCall);
 document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
 }
 }
 else
 {
 jsApiCall();
 }
 }
</script>

必須要用Html.Raw,不然json解析不對,無法支付。這個時候點擊頁面,會出現(xiàn)微信的加載效果,但別高興的太早,還是會出錯,出現(xiàn)一個“3當前的URL未注冊”

微信公眾平臺支付開發(fā)詳解

原因就在于,需要在公眾號中設(shè)置支付目錄。而這個支付目錄是大小寫敏感的,所以你得多試幾次。直到彈出輸入密碼的窗口才是真的流程正確了。然后支付成功之后馬上就可以收到js中的回調(diào),這個時候你可以去處理你的訂單和業(yè)務邏輯。

官方文檔:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_3

官方demo:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持服務器之家!

原文鏈接:http://www.cnblogs.com/stoneniqiu/p/6308813.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 精品高潮呻吟99AV无码视频 | 国产成人福利美女观看视频 | 久久久久久久尹人综合网亚洲 | 国产午夜亚洲精品理论片不卡 | 好爽好舒服视频 | 女人全身裸露无遮挡免费观看 | 亚洲黄色大片 | 高h全肉动漫在线观看免费 高h辣h双处全是肉军婚 | 日韩性公交车上xxhd免费 | 国产午夜一区二区在线观看 | 女上男下gifxxoo动态视频 | 亚洲精品久久玖玖玖玖 | 日本道高清 | 国产精品久久久久久久福利院 | 小泽玛丽av无码观看 | 13日本xxxxxxxxx18| asianfemdom妍妍女王 | 欧美福利在线观看 | 韩国伊人 | 97久久精品午夜一区二区 | 潘甜甜在线观看 | 免费看伦理片 | 国产精品视频免费一区二区三区 | 扒开老师挠尿口到崩溃刑罚 | 婚色阿花在线全文免费笔 | 国产一区国产二区国产三区 | 国产成人免费片在线观看 | 亚洲成人三级 | 日韩欧美国产一区 | 日本免费全黄一级裸片视频 | 亚洲精品www久久久久久久软件 | 日本肥熟| 欧美精品一线二线大片 | 成人免费福利网站在线看 | 亚洲人成在线观看一区二区 | 亚洲国产成人在线 | 欧美一区高清 | 色综合伊人色综合网站中国 | 国产一级毛片外aaaa | 四虎在线免费 | 情人我吃糖果小说 |