


Detailed graphic explanation of WeChat public platform payment development
Mar 14, 2017 pm 02:41 PMThis article mainly introduces the implementation methods and steps of public account payment in WeChat development. It has a very good reference value. Let’s take a look at it with the editor.
Public account payment is the function of calling up WeChat payment on the H5 page in WeChat and making payment without scanning the QR code. The first thing to make clear when implementing this function is that only the appid that matches the merchant number mch_id can pay successfully. When the merchant account is successfully registered, relevant information will be sent to the mailbox. A key to arousing payment is to rely on openid to obtain unified orders. The openid corresponds to the appid one-to-one. That is to say, if the appid you use to log in is not the appid of the official account, the openid you get will not be able to trigger payment in the official account (there will be an error that the appid does not match the merchant account). I once took a detour here because WeChat's open platform can create website applications. It also has an appid and appsecret, and you can also log in with one click in WeChat.
Business process
The following is the official process of WeChat. It seems a bit complicated. The key point is to get the unified order interfacereturnedjsonString, others can be basically correct according to the official demo. Here are a few details.
Create order
Before calling the WeChat official account for payment, we must first create the order ourselves. For example, a recharge order. The main thing is to determine the amount first and then proceed to the next step.
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}); }
Call unified order
After the order is successfully created, the page jumps to the payment page. This time Follow the official process to get prepay_id and paySign. The WeChat demo provides a jsApiPayobject. But this object requires a page object to be initialized.
[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(); }
In MVC we can simply change it. That is, replace the page object with httpContext. Then the methods inside can be used directly.
JsApiPayMvc:
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> /// 保存頁面對象,因?yàn)橐陬惖姆椒ㄖ惺褂肞age的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的返回?cái)?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ù) * 更詳細(xì)的說明請參考網(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", //隨機(jī)串 * "package" : "prepay_id=u802345jgfjsdfgsdg888", * "signType" : "MD5", //微信簽名方式: * "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信簽名 * } * @return string 微信瀏覽器調(diào)起JSAPI時的輸入?yún)?shù),json格式可以直接做參數(shù)用 * 更詳細(xì)的說明請參考網(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; } } }
This page can be debugged locally, which is more convenient Confirm whether the parameters are OK.
Arouse Payment
An example of the official page is as follows: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter= 7_7&index=6 But the main parameters (mark part) are generated by the background, which is the ViewBag.wxJsApiParam
function onBridgeReady(){ WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId" : "wx2421b1c4370ec43b", //公眾號名稱,由商戶傳入 "timeStamp":" 1395712654", //時間戳,自1970年以來的秒數(shù) "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //隨機(jī)串 "package" : "prepay_id=u802345jgfjsdfgsdg888", "signType" : "MD5", //微信簽名方式: "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信簽名 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) {} // 使用以上方式判斷前端返回,微信團(tuán)隊(duì)鄭重提示:res.err_msg將在用戶支付成功后返回 ok,但并不保證它絕對可靠。 } ); }
in the previous step, so in MVC Write like this:
@{ 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>
You must use Html.Raw, otherwise the json parsing is incorrect and payment cannot be made. When you click on the page at this time, the WeChat loading effect will appear, but don’t get too happy too early, an error will still occur, and a “3 The current URL is not registered”
reason will appear. Yes, you need to set up a payment directory in the official account. This payment directory is case-sensitive, so you have to try a few times. The process is really correct until the window for entering the password pops up. Then you can receive the callback in js immediately after the payment is successful. At this time, you can process your order and business logic.
The above is the detailed content of Detailed graphic explanation of WeChat public platform payment development. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)