Dieses Mal werde ich Ihnen die Entwicklung der offiziellen Kontozahlungsschnittstelle vorstellen. Was sind die Vorsichtsmaßnahmen bei der Entwicklung der offiziellen Kontozahlungsschnittstelle?
Offizielle Kontozahlung ist die Funktion, die WeChat-Zahlung auf der H5-Seite in WeChat aufzurufen und die Zahlung durchzuführen, ohne den QR-Code zu scannen. Bei der Implementierung dieser Funktion muss zunächst klargestellt werden, dass nur die Appid erfolgreich bezahlen kann, die mit der Händlernummer mch_id übereinstimmt. Wenn das Händlerkonto erfolgreich registriert ist, werden relevante Informationen an die Mailbox gesendet. Ein Schlüssel zur Zahlungsanreizung besteht darin, sich auf openid zu verlassen, um einheitliche Bestellungen zu erhalten. Die openid entspricht der appid eins zu eins. Das heißt, wenn die App-ID, mit der Sie sich anmelden, nicht die App-ID des offiziellen Kontos ist, kann die von Ihnen erhaltene OpenID keine Zahlung auf dem offiziellen Konto auslösen (es wird ein Fehler angezeigt, dass die App-ID nicht mit der App-ID übereinstimmt). Händlerkonto). Ich habe einmal einen Umweg hierher gemacht, weil die offene Plattform von WeChat Website-Anwendungen erstellen kann. Sie verfügt auch über eine App-ID und ein App-Geheimnis und Sie können sich auch mit einem Klick bei WeChat anmelden.
Das Folgende ist der offizielle Prozess von WeChat. Der entscheidende Punkt besteht darin, die JSON-Zeichenfolge von der einheitlichen Bestellschnittstelle zurückzugeben korrekt gemäß der offiziellen Demo unten Lassen Sie mich Ihnen ein paar Details erzählen.
Bevor wir das offizielle WeChat-Konto zur Zahlung aufrufen, müssen wir die Bestellung zunächst selbst erstellen. Zum Beispiel eine Aufladebestellung. Die Hauptsache ist, zuerst den Betrag zu bestimmen und dann mit dem nächsten Schritt fortzufahren.
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}); }
Nachdem die Bestellung erfolgreich erstellt wurde, springt die Seite zur Zahlungsseite. Befolgen Sie zu diesem Zeitpunkt den offiziellen Prozess, um prepay_id und paySign zu erhalten, die bereitgestellt werden in der WeChat-Demo Ein jsApiPay-Objekt. Für dieses Objekt muss jedoch ein Seitenobjekt initialisiert werden.
[LoginValid] public ActionResult H5Pay(string orderNumber) { var user = _workContext.CurrentUser; var order = _paymentService.GetOrderByOrderNumber(orderNumber); //判断订单是否存在 //订单是否已经支付了 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调起JS API参数 ViewBag.unifiedOrder = unifiedOrderResult.ToPrintStr(); ViewBag.OrderNumber = order.OrderNumber; return View(); }
In MVC können wir es einfach ändern. Ersetzen Sie also das Seitenobjekt durch httpContext. Dann können die darin enthaltenen Methoden direkt verwendet werden.
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> /// 保存页面对象,因为要在类的方法中使用Page的Request对象 /// </summary> public HttpContextBase context { get; set; } /// <summary> /// openid用于调用统一下单接口 /// </summary> public string openid { get; set; } /// <summary> /// access_token用于获取收货地址js函数入口参数 /// </summary> public string access_token { get; set; } /// <summary> /// 商品金额,用于统一下单 /// </summary> public int total_fee { get; set; } /// <summary> /// 统一下单接口返回结果 /// </summary> public WxPayData unifiedOrderResult { get; set; } public JsApiPayMvc(HttpContextBase _context) { context = _context; } /** * * 网页授权获取用户基本信息的全部过程 * 详情请参看网页授权获取用户基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html * 第一步:利用url跳转获取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 { //构造网页授权获取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 { //触发微信返回code码 context.Response.Redirect(url);//Redirect函数会抛出ThreadAbortException异常,不用处理这个异常 } catch(System.Threading.ThreadAbortException ex) { } } } /** * * 通过code换取网页授权access_token和openid的返回数据,正确时返回的JSON数据包如下: * { * "access_token":"ACCESS_TOKEN", * "expires_in":7200, * "refresh_token":"REFRESH_TOKEN", * "openid":"OPENID", * "scope":"SCOPE", * "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL" * } * 其中access_token可用于获取共享收货地址 * openid是微信支付jsapi支付接口统一下单时必须的参数 * 更详细的说明请参考网页授权获取用户基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html * @失败时抛异常WxPayException */ public void GetOpenidAndAccessTokenFromCode(string code) { try { //构造获取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以获取数据 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()); } } /** * 调用统一下单,获得下单结果 * @return 统一下单结果 * @失败时抛异常WxPayException */ public WxPayData GetUnifiedOrderResult() { //统一下单 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; } /** * * 从统一下单成功返回的数据中获取微信浏览器调起jsapi支付所需的参数, * 微信浏览器调起JSAPI时的输入参数格式如下: * { * "appId" : "wx2421b1c4370ec43b", //公众号名称,由商户传入 * "timeStamp":" 1395712654", //时间戳,自1970年以来的秒数 * "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //随机串 * "package" : "prepay_id=u802345jgfjsdfgsdg888", * "signType" : "MD5", //微信签名方式: * "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 * } * @return string 微信浏览器调起JSAPI时的输入参数,json格式可以直接做参数用 * 更详细的说明请参考网页端调起支付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函数入口参数,详情请参考收货地址共享接口:http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_9 * @return string 共享收货地址js函数需要的参数,json格式可以直接做参数使用 */ public string GetEditAddressParameters() { string parameter = ""; try { string host = context.Request.Url.Host; string path = context.Request.Path; string queryString = context.Request.Url.Query; //这个地方要注意,参与签名的是网页授权获取用户信息时微信后台回传的完整url string url = "http://" + host + path + queryString; //构造需要用SHA1算法加密的数据 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函数入口参数 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")); //转为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; } } }
Code anzeigen
Diese Seite kann lokal debuggt werden, und es ist bequemer zu bestätigen, ob die Parameter in Ordnung sind.
Ein Beispiel für die offizielle Seite ist wie folgt: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index= 6 Aber die Hauptsache ist, dass die Parameter (Markierungsteil) durch den Hintergrund generiert werden, nämlich ViewBag.wxJsApiParam
function onBridgeReady(){ WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId" : "wx2421b1c4370ec43b", //公众号名称,由商户传入 "timeStamp":" 1395712654", //时间戳,自1970年以来的秒数 "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,但并不保证它绝对可靠。 } ); }
im vorherigen Schritt, also sollte es in MVC so geschrieben werden:
@{ ViewBag.Title = "微信支付"; Layout = "~/Views/Shared/_Layout.cshtml"; }<p class="page" id="Wxpayment"> <p class="content"> <p>订单详情:@Html.Raw(ViewBag.unifiedOrder)</p> <button id="h5pay" onclick="callpay()">支付</button> </p> <input type="hidden" value="@ViewBag.OrderNumber" id="ordernum"/></p> <script type="text/javascript"> //调用微信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>
muss Html .Raw verwenden, sonst ist die JSON-Analyse falsch und die Zahlung ist nicht möglich. Klicken Sie zu diesem Zeitpunkt auf die Seite und der WeChat-Ladeeffekt wird angezeigt, aber freuen Sie sich nicht zu früh. Es tritt immer noch ein Fehler auf und die Meldung „3 Die aktuelle URL ist nicht registriert“ wird angezeigt
Der Grund ist: Ja, Sie müssen im offiziellen Konto ein Zahlungsverzeichnis einrichten. Bei diesem Zahlungsverzeichnis wird die Groß-/Kleinschreibung beachtet, daher müssen Sie es mehrmals versuchen. Der Vorgang ist wirklich korrekt, bis das Fenster zur Eingabe des Passworts erscheint. Dann können Sie den Rückruf in js sofort nach erfolgreicher Zahlung erhalten. Zu diesem Zeitpunkt können Sie Ihre Bestellung und Geschäftslogik bearbeiten.
Wenn es sich um eine Produktionsumgebung handelt, müssen wir sie an mehreren Stellen aufrufen und erneut kapseln.
function jsApiCall(json, success, fail) { WeixinJSBridge.invoke( 'getBrandWCPayRequest', json,//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") { //充值进去 要区分是出题充值 还是购买悬赏 前者冲到他的钱包 //后者直接冲到系统账户 if (success) success(); } if (res.err_msg == 'get_brand_wcpay_request:cancel') { // alert('取消支付'); if (fail)fail(); } } ); }function callpay(json,success,fail) { if (typeof WeixinJSBridge == "undefined") { alert("请在微信中打开!"); if (document.addEventListener) { document.addEventListener('WeixinJSBridgeReady', jsApiCall, false); } else if (document.attachEvent) { document.attachEvent('WeixinJSBridgeReady', jsApiCall); document.attachEvent('onWeixinJSBridgeReady', jsApiCall); } } else { jsApiCall(json, success, fail); } }
Code anzeigen
[LoginValid] public ActionResult H5PayJson(string orederId) { var user = _workContext.CurrentUser; var order = _paymentService.GetOrderByOrderNumber(orederId); //判断订单是否存在 //订单是否已经支付了 var openid = user.OpenId; var jsApipay = new JsApiPayMvc(ControllerContext.HttpContext) { openid = openid, total_fee = (int) order.Amount*100 }; try { jsApipay.GetUnifiedOrderResult(); return Json(jsApipay.GetJsApiParameters());//实际还是字符串 } catch (Exception e) { //统一下单失败 return Json(new PortalResult(false, e.Message)); } }
Bei Aufruf löst dies direkt die Zahlung aus. Wenn der eingehende JSON jedoch kein JSON-Objekt ist, bleibt die WeChat-Ladeanimation immer hängen.
$.post("/Checkout/H5PayJson", { orederId: orderId }, function (jsondata) { var jdata = JSON.parse(jsondata); if (jdata.appId) { callpay(jdata, function () { $.post("/payment/WeiXinPaySuccess", { ordernumber: orderId }, function (paymentdata) { if (paymentdata.IsSuccess === true) { submitQuestion(); } else { $.alert(paymentdata.Message); } }); }, function () { $.alert("你已取消支付!"); }); } else { alert("统一下单失败!"); } });
Ich glaube, dass Sie die Methode beherrschen, nachdem Sie den Fall in diesem Artikel gelesen haben. Weitere spannende Informationen finden Sie in anderen verwandten Artikeln auf der chinesischen PHP-Website.
Empfohlene Lektüre:
Die Verwendung der automatischen Aktualisierung und Analyse von Webpacks
Detaillierte Erläuterung des Hot-Ersatzes des Webpack-Moduls
Die Methode, zuerst JS-Ereignisse zu veröffentlichen und dann zu abonnieren
Das obige ist der detaillierte Inhalt vonEntwicklung einer offiziellen Schnittstelle zur Kontozahlung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!