.NET WeChat パブリック アカウント開発 (5.0 WeChat 支払い) の詳細な例
1. 前書き
この機能を実行する前に、最初にやらなければならないことは、この WeChat 支払いを行う方法、どこから始めるべきか、公式の SDK の指示は何か、公式の指示はあるかどうかを考えることです。デモは 1 つですか、申請するインターフェイスも含め、上司から与えられた情報が完全かどうか。
私は上司の勧めで少し調べた結果、これを完成させました。私の能力には限界があるので、ここでいくつかまとめておきます。何を言っても、それは良くありません、皆さんが我慢してくれることを願っています。
2. 開発前の準備。
1.0 WeChat Pay 公式開発者ドキュメント
2.0 公式デモのダウンロード C# を使用しているため、.net バージョンを選択しましたが、この公式デモはまったく実行されません
3.0 公式デモの実行ソリューション
4.0 WeChat Pay 公式 .netバージョン交渉なしで騙します
5.0開発前のWeChatパブリックプラットフォームの一部の設定は、必ず注意深く確認してください。
これらの準備が完了すると、WeChat 支払いには 2 つのタイプがあることがわかりました。1. オリジナルのもの、2. jsapi によって直接呼び出されるもの。2 つ目は、私のプロジェクトで使用されます
いくつかのビジネス ロジック処理を経て、次のようになりました。注文詳細ページに移動し、支払いボタンをクリックする必要があります。支払いページの pay.aspx コードは次のとおりです。
フロント ページ:
<script type="text/javascript"> //调用微信JS api 支付 function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest', <%=wxJsApiParam%>,//josn串 function (res) { if (res.err_msg == "get_brand_wcpay_request:ok") { var OrderId=$("#OrderId").val(); var orderProductName=$("#orderProductName").val(); var orderMoneySum=$("#orderMoneySum").val(); window.location.href="http://www.baidu.aspx?OrderId="+OrderId+"&orderMoneySum="+orderMoneySum+"&orderProductName="+orderProductName;//支付成功后的跳转页面 }else { WeixinJSBridge.call('closeWindow'); } } ); } function callpay() { if (typeof WeixinJSBridge == "undefined") { if (document.addEventListener) { document.addEventListener('WeixinJSBridgeReady', jsApiCall, false); } else if (document.attachEvent) { document.attachEvent('WeixinJSBridgeReady', jsApiCall); document.attachEvent('onWeixinJSBridgeReady', jsApiCall); } } else { jsApiCall(); } } </script> <body> <p> <br /> <br /> <br /> <input type="hidden" id="OrderId" name="OrderId" value="<%=OrderId %>"/> <input type="hidden" id="orderMoneySum" name="orderMoneySum" value="<%=orderMoneySum %>"/> <input type="hidden" id="orderProductName" name="orderProductName" value="<%=orderProductName %>"/> <span class="fLeft" style="font-size:20px;color:Purple"> 您确认付款<label style="font-size:25px;color:Red"><%=Money%></label>元...</span> <p><button type="button" class="btn-pay" title="确认支付" onclick="callpay()">立即支付</button></p> </p> </body> </html>
注意すべき点:
WeChat JS API WeChat の内蔵ブラウザでのみ使用でき、他のブラウザからの呼び出しは無効です。 WeChat は、販売者のフロントエンド Web ページが呼び出すための getBrandWCPayRequest インターフェイスを提供します。販売者が支払いを開始する権限を持っている場合、WeChat は販売者の支払い権限を識別します。 このセクションでは、主に支払い前のインターフェイス呼び出しルールを紹介します。以下の支払いステータス メッセージ通知メカニズムを参照してください。インターフェイスに注意する必要があります。受信パラメータはすべて文字列型です。
getBrandWCPayRequest パラメータを表 6-5 に示します。
パラメータ | 名前 | 必須 | 形式
| 説明 |
公式アカウント ID | は | 文字列型 | 販売者が支払い許可を持って公式アカウントを正常に登録した後に取得できます | |
タイムスタンプ。 | は、マーチャントによって生成される 32 バイト未満の | 文字列型であり、1970 年 1 月 1 日の 00:00:00 から現在 (現在時刻) までの秒数です。最終的には文字に変換する必要があります 文字列形式 | nonceStr | |
は 32 バイト未満の | 文字列型です | A ランダムによって生成された文字列販売者; | パッケージ | |
は、4096バイト未満の | 文字列型です | この文字列に。特定の構成スキームについては、インターフェースの使用方法を参照してください。 パッケージ グループ パッケージは、仕様に従ってマーチャントによってスプライシングされた後に渡されます。 | 文字列型で、パラメータ値は「SHA1」です | ドキュメントに示されているように入力します。現在サポートされているのはSHA1のみです |
paySign | 签名 | 是 | 字符串类型 | 商户将接口列表中的参数按照指定方式迚行签名,签名方式使用signType中标示的签名方式,具体签名方案参见接口使用说明中签名帮劣;由商户按照规范签名后传入; |
表6-5 getBrandWCPayRequest参数
getBrandWCPayRequest返回值如表6-6所示。
返回值 | 说明 |
err_msg | get_brand_wcpay_request:ok 支付成功 |
表6-6 getBrandWCPayRequest返回值
JS API的返回结果 get_brand_wcpay_request:ok 仅在用户成功完成支付时返回。由于前端交互复杂,get_brand_wcpay_request:cancel 或者 get_brand_wcpay_request:fail 可以统一处理为用户遇到错误或者 主动放弃,不必细化区分。
pay.aspx后台页面代码:
wxJsApiParam { ; ; } Money { ; OrderId { ; orderMoneySum { ; ; } orderProductName { ; ; } Page_Load( (!= JsApiPay( total_fee = Request[ orderMoneySum = ParkName = Request[= ParkName+= Request[ (.IsNullOrWhiteSpace(total_fee)||total_fee== WxPayException( + + =.Parse((Convert.ToDouble(total_fee)*= (Convert.ToDouble(jsApiPay.total_fee)/= (Common.OpenId == WxPayException(=== jsApiPay.GetJsApiParameters(); + + ex.InnerException.Message + + + ex.Message +
在这里需要我们注意的是:jsApiPay.openid = common.GetOpenId();
在支付的时候,我们需要首先获取用户的openId,然而获取用户openId的这个过程我们首先要进行Oauth2认证,在官方的demo中提供了JsApiPay.cs这个核心类库,里面已经有这个GetOpenidAndAccessToken()方法 。我这里是拿过来写成了自己的一个公共帮助类。Common.cs
/// <summary> /// 公共帮助类 /// </summary> public class Common { private HttpContext Context { get; set; } public static string OpenId = "Openid"; public static string access_token = "access_token"; #region 构造函数 /// <summary> /// 构造函数 /// </summary> /// <param name="Context"></param> public Common(HttpContext context) { this.Context = context; } #endregion #region 通过code换取AccessToken /// <summary> /// 通过code换取AccessToken /// </summary> public void GetOpenidAndAccessToken() { if (!string.IsNullOrEmpty(Context.Request.QueryString["code"])) { //获取code码,以获取openid和access_token string code = Context.Request.QueryString["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(); try { //触发微信返回code码 Context.Response.Redirect(url);//Redirect函数会抛出ThreadAbortException异常,不用处理这个异常 } catch (System.Threading.ThreadAbortException ex) { } } } #endregion #region 通过用户授权获取AccessToken和OpenId /// <summary> /// 通过用户授权获取AccessToken和OpenId /// </summary> /// <param name="code"></param> 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); //保存access_token,用于收货地址获取 JsonData jd = JsonMapper.ToObject(result); access_token = (string)jd["access_token"]; //获取用户openid OpenId = (string)jd["openid"]; } catch (Exception ex) { throw new WxPayException(ex.ToString()); } } #endregion #region 获取OpenId /// <summary> /// 获取OpenId /// </summary> /// <param name="postStr"></param> /// <returns></returns> public string GetOpenId() { Common common = new Common(Context); common.GetOpenidAndAccessToken(); return OpenId; } #endregion }
public class JsApiPay { /// <summary> /// 保存页面对象,因为要在类的方法中使用Page的Request对象 /// </summary> private Page page {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> /// 订单Id /// </summary> public string orderid { get; set; } /// <summary> /// 统一下单接口返回结果 /// </summary> public WxPayData unifiedOrderResult { get; set; } public JsApiPay(Page page) { this.page = page; } /** * * 网页授权获取用户基本信息的全部过程 * 详情请参看网页授权获取用户基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html * 第一步:利用url跳转获取code * 第二步:利用code去获取openid和access_token * */ public void GetOpenidAndAccessToken() { if (!string.IsNullOrEmpty(page.Request.QueryString["code"])) { //获取code码,以获取openid和access_token string code = page.Request.QueryString["code"]; //Log.Debug(this.GetType().ToString(), "Get code : " + code); GetOpenidAndAccessTokenFromCode(code); } else { //构造网页授权获取code的URL string host = page.Request.Url.Host; //Log.Debug(this.GetType().ToString(), "host" + host); string path = page.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码 page.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); data.SetValue("orderid", orderid); 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; } public WxPayData GetUnifiedOrderResult(string body) { //统一下单 WxPayData data = new WxPayData(); data.SetValue("body", body); //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() { 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(); 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 = page.Request.Url.Host; string path = page.Request.Path; string queryString = page.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; } }
JsApiPay
微信支付协议接口数据类WxPayData.cs官方都有相应的代码.
/// <summary> /// 微信支付协议接口数据类,所有的API接口通信都依赖这个数据结构, /// 在调用接口之前先填充各个字段的值,然后进行接口通信, /// 这样设计的好处是可扩展性强,用户可随意对协议进行更改而不用重新设计数据结构, /// 还可以随意组合出不同的协议数据包,不用为每个协议设计一个数据包结构 /// </summary> public class WxPayData { public WxPayData() { } //采用排序的Dictionary的好处是方便对数据包进行签名,不用再签名之前再做一次排序 private SortedDictionary<string, object> m_values = new SortedDictionary<string, object>(); /** * 设置某个字段的值 * @param key 字段名 * @param value 字段值 */ public void SetValue(string key, object value) { m_values[key] = value; } /** * 根据字段名获取某个字段的值 * @param key 字段名 * @return key对应的字段值 */ public object GetValue(string key) { object o = null; m_values.TryGetValue(key, out o); return o; } /** * 判断某个字段是否已设置 * @param key 字段名 * @return 若字段key已被设置,则返回true,否则返回false */ public bool IsSet(string key) { object o = null; m_values.TryGetValue(key, out o); if (null != o) return true; else return false; } /** * @将Dictionary转成xml * @return 经转换得到的xml串 * @throws WxPayException **/ public string ToXml() { //数据为空时不能转化为xml格式 if (0 == m_values.Count) { Log.Error(this.GetType().ToString(), "WxPayData数据为空!"); throw new WxPayException("WxPayData数据为空!"); } string xml = "<xml>"; foreach (KeyValuePair<string, object> pair in m_values) { //字段值不能为null,会影响后续流程 if (pair.Value == null) { Log.Error(this.GetType().ToString(), "WxPayData内部含有值 为null的字段!"); throw new WxPayException("WxPayData内部含有值为null的字段!"); } if (pair.Value.GetType() == typeof(int)) { xml += "<" + pair.Key + ">" + pair.Value + "</" + pair.Key + ">"; } else if (pair.Value.GetType() == typeof(string)) { xml += "<" + pair.Key + ">" + "<![CDATA [" + pair.Value + "]]></" + pair.Key + ">"; } else//除了string和int类型不能含有其他数据类型 { Log.Error(this.GetType().ToString(), "WxPayData字段数据类 型错误!"); throw new WxPayException("WxPayData字段数据类型错误!"); } } xml += "</xml>"; return xml; } /** * @将xml转为WxPayData对象并返回对象内部的数据 * @param string 待转换的xml串 * @return 经转换得到的Dictionary * @throws WxPayException */ public SortedDictionary<string, object> FromXml(string xml) { if (string.IsNullOrEmpty(xml)) { Log.Error(this.GetType().ToString(), "将空的xml串转换为 WxPayData不合法!"); throw new WxPayException("将空的xml串转换为WxPayData不合法!"); } XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(xml); XmlNode xmlNode = xmlDoc.FirstChild;//获取到根节点<xml> XmlNodeList nodes = xmlNode.ChildNodes; foreach (XmlNode xn in nodes) { XmlElement xe = (XmlElement)xn; m_values[xe.Name] = xe.InnerText;//获取xml的键值对到WxPayData内部的数据中 } try { //2015-06-29 错误是没有签名 if(m_values["return_code"] != "SUCCESS") { return m_values; } CheckSign();//验证签名,不通过会抛异常 } catch(WxPayException ex) { throw new WxPayException(ex.Message); } return m_values; } /** * @Dictionary格式转化成url参数格式 * @ return url格式串, 该串不包含sign字段值 */ public string ToUrl() { string buff = ""; foreach (KeyValuePair<string, object> pair in m_values) { if (pair.Value == null) { Log.Error(this.GetType().ToString(), "WxPayData内部含有值 为null的字段!"); throw new WxPayException("WxPayData内部含有值为null的字段!"); } if (pair.Key != "sign" && pair.Value.ToString() != "") { buff += pair.Key + "=" + pair.Value + "&"; } } buff = buff.Trim('&'); return buff; } /** * @Dictionary格式化成Json * @return json串数据 */ public string ToJson() { string jsonStr = JsonMapper.ToJson(m_values); return jsonStr; } /** * @values格式化成能在Web页面上显示的结果(因为web页面上不能直接输出xml格式的字符串) */ public string ToPrintStr() { string str = ""; foreach (KeyValuePair<string, object> pair in m_values) { if (pair.Value == null) { Log.Error(this.GetType().ToString(), "WxPayData内部含有值 为null的字段!"); throw new WxPayException("WxPayData内部含有值为null的字段!"); } str += string.Format("{0}={1}<br>", pair.Key, pair.Value.ToString()); } Log.Debug(this.GetType().ToString(), "Print in Web Page : " + str); return str; } /** * @生成签名,详见签名生成算法 * @return 签名, sign字段不参加签名 */ public string MakeSign() { //转url格式 string str = ToUrl(); //在string后加入API KEY str += "&key=" + WxPayConfig.KEY; //MD5加密 var md5 = MD5.Create(); var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(str)); var sb = new StringBuilder(); foreach (byte b in bs) { sb.Append(b.ToString("x2")); } //所有字符转为大写 return sb.ToString().ToUpper(); } /** * * 检测签名是否正确 * 正确返回true,错误抛异常 */ public bool CheckSign() { //如果没有设置签名,则跳过检测 if (!IsSet("sign")) { Log.Error(this.GetType().ToString(), "WxPayData签名存在但不合法 !"); throw new WxPayException("WxPayData签名存在但不合法!"); } //如果设置了签名但是签名为空,则抛异常 else if(GetValue("sign") == null || GetValue("sign").ToString() == "") { Log.Error(this.GetType().ToString(), "WxPayData签名存在但不合 法!"); throw new WxPayException("WxPayData签名存在但不合法!"); } //获取接收到的签名 string return_sign = GetValue("sign").ToString(); //在本地计算新的签名 string cal_sign = MakeSign(); if (cal_sign == return_sign) { return true; } Log.Error(this.GetType().ToString(), "WxPayData签名验证错误!"); throw new WxPayException("WxPayData签名验证错误!"); } /** * @获取Dictionary */ public SortedDictionary<string, object> GetValues() { return m_values; } }
WxPayData
配置文件信息
/** * 配置账号信息 */ public class WxPayConfig { //=======【基本信息设置】===================================== /* 微信公众号信息配置 * APPID:绑定支付的APPID(必须配置) * MCHID:商户号(必须配置) * KEY:商户支付密钥,参考开户邮件设置(必须配置) * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置) */ public const string APPID = "wx14e3e56f3"; public const string MCHID = "12352"; public const string KEY = "BB6BE71D7CED49A79409C9"; public const string APPSECRET = "76eb33f66129692da1624f1"; //=======【证书路径设置】===================================== /* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要) */ public const string SSLCERT_PATH = "cert/apiclient_cert.p12"; public const string SSLCERT_PASSWORD = "123502"; //=======【支付结果通知url】===================================== /* 支付结果通知回调url,用于商户接收支付结果 */ public const string NOTIFY_URL = "http://www.baidu.com/ResultPay.aspx"; //=======【商户系统后台机器IP】===================================== /* 此参数可手动配置也可在程序中自动获取 */ public const string IP = "150.24.91.151"; //=======【代理服务器设置】=================================== /* 默认IP和端口号分别为0.0.0.0和0,此时不开启代理(如有需要才设置) */ public const string PROXY_URL = "http://10.152.18.220:8080"; //=======【上报信息配置】=================================== /* 测速上报等级,0.关闭上报; 1.仅错误时上报; 2.全量上报 */ public const int REPORT_LEVENL = 1; //=======【日志级别】=================================== /* 日志等级,0.不输出日志;1.只输出错误信息; 2.输出错误和正常信息; 3.输出错误信息、正常信息和调试信息 */ public const int LOG_LEVENL =3; }
WxPayConfig
接着我们在看2行关键的代码:
WxPayData unifiedOrderResult == jsApiPay.GetJsApiParameters();
此时如果wxJsApiParam变量能够顺利拿到值,那么我们前台页面的:<%=wxJsApiParam%>z这里就可以获取到我们要传递的参数,这时候就可以调用微信支付的接口,打开我们的付款页面如图所示:
//调用微信JS api 支付 function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest', <%=wxJsApiParam%>,//josn串 function (res) { if (res.err_msg == "get_brand_wcpay_request:ok") { var OrderId=$("#OrderId").val(); var orderProductName=$("#orderProductName").val(); var orderMoneySum=$("#orderMoneySum").val(); window.location.href="http://www.baodu.com/PaySkip.aspx?OrderId="+OrderId+"&orderMoneySum="+orderMoneySum+"&orderProductName="+orderProductName; }else { WeixinJSBridge.call('closeWindow'); } } ); }
(JsApiPay.cs)得到下单结果:
public WxPayData GetUnifiedOrderResult(string body) { //统一下单 WxPayData data = new WxPayData(); data.SetValue("body", body); data.SetValue("out_trade_no", WxPayApi.GenerateOutTradeNo()); data.SetValue("total_fee", total_fee); 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; }
(WxPayApi.cs)统一下单接口:
/** * * 统一下单 * @param WxPaydata inputObj 提交给统一下单API的参数 * @param int timeOut 超时时间 * @throws WxPayException * @return 成功时返回,其他抛异常 */ public static WxPayData UnifiedOrder(WxPayData inputObj, int timeOut = 6) { string url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //检测必填参数 if (!inputObj.IsSet("out_trade_no")) { throw new WxPayException("缺少统一支付接口必填参数out_trade_no!"); } else if (!inputObj.IsSet("body")) { throw new WxPayException("缺少统一支付接口必填参数body!"); } else if (!inputObj.IsSet("total_fee")) { throw new WxPayException("缺少统一支付接口必填参数total_fee!"); } else if (!inputObj.IsSet("trade_type")) { throw new WxPayException("缺少统一支付接口必填参数trade_type!"); } //关联参数 if (inputObj.GetValue("trade_type").ToString() == "JSAPI" && !inputObj.IsSet("openid")) { throw new WxPayException("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!"); } if (inputObj.GetValue("trade_type").ToString() == "NATIVE" && !inputObj.IsSet("product_id")) { throw new WxPayException("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!"); } //异步通知url未设置,则使用配置文件中的url if (!inputObj.IsSet("notify_url")) { inputObj.SetValue("notify_url", WxPayConfig.NOTIFY_URL);//异步通知url } inputObj.SetValue("appid", WxPayConfig.APPID);//公众账号ID inputObj.SetValue("mch_id", WxPayConfig.MCHID);//商户号 inputObj.SetValue("spbill_create_ip", WxPayConfig.IP);//终端ip inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串 //签名 inputObj.SetValue("sign", inputObj.MakeSign()); string xml = inputObj.ToXml(); var start = DateTime.Now; string response = HttpService.Post(xml, url, false, timeOut); var end = DateTime.Now; int timeCost = (int)((end - start).TotalMilliseconds); WxPayData result = new WxPayData(); result.FromXml(response); ReportCostTime(url, timeCost, result);//测速上报 return result; }
四.最终开发的效果
五.微信公众号开发系列导航
1.0初始微信公众号
2.0创建自定义菜单
3.0查询自定义菜单
4.0公众号消息处理
5.0微信支付
6.0模板消息
以上が.NET WeChat パブリック アカウント開発 (5.0 WeChat 支払い) の詳細な例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









WeChat では、ユーザーは支払いパスワードを入力して購入できますが、支払いパスワードを忘れた場合はどうすればよいでしょうか?ユーザーが支払いパスワードを忘れた場合は、[マイサービス] - [ウォレット] - [支払い設定] - に移動して支払いパスワードを回復する必要があります。決済パスワードを忘れた場合の確認方法については、具体的な操作方法を以下で詳しくご紹介しますので、ぜひご覧ください。 WeChat の使い方チュートリアル. WeChat の支払いパスワードを忘れた場合、どのように確認しますか? 回答: マイサービス - ウォレット - 支払い設定 - 支払いパスワードを忘れた場合 具体的な方法: 1. まず、[マイ] をクリックします。 2. 中のサービスをクリックします。 3. 内部のウォレットをクリックします。 4. 支払い設定を見つけます。 5. 「支払いパスワードを忘れた場合」をクリックします。 6. 確認のために自分の情報を入力します。 7. 次に、新しい支払いパスワードを入力して変更します。

WeChat 支払いパスワードを忘れた場合の解決策: 1. WeChat アプリを開き、右下隅の「I」をクリックしてパーソナル センター ページに入ります; 2. パーソナル センター ページで、「支払う」をクリックして支払いページに入ります; 3.支払いページで、右上隅の「...」をクリックして支払い管理ページに入ります; 4. 支払い管理ページで、「支払いパスワードを忘れた場合」を見つけてクリックします; 5. ページの指示に従って、個人情報を入力します。本人確認が完了すると、「顔をスワイプして取得する」または「キャッシュカード情報を認証して取得する」方法からパスワードなどを取得することができます。

Meituan テイクアウト アプリには多くの食品や軽食の店があり、すべての携帯電話ユーザーは自分のアカウントを通じてログインします。個人の配達先住所と連絡先番号を追加して、最も便利なテイクアウト サービスをお楽しみください。ソフトウェアのホームページを開き、製品キーワードを入力し、オンラインで検索すると、対応する製品の結果が表示されます。上下にスワイプするだけで購入して注文できます。また、プラットフォームは、配達先住所に基づいて、レビューの高い近くの数十のレストランを推奨しますユーザーが提供する. ストアはさまざまな支払い方法も設定できます. ワンクリックで注文を完了できます. ライダーはすぐに配達を手配でき、配達速度は非常に速いです. テイクアウト用の赤い封筒もあります. Meituan のテイクアウト ユーザー向けにエディターがオンラインで詳細に表示され、WeChat 支払いの設定方法を説明します。 1. 製品を選択した後、注文を送信し、[今すぐ] をクリックします。

誰もが何もすることがないとき、Xianyuプラットフォームを閲覧することを選択します.このプラットフォームには多数の製品があることがわかり、誰もがさまざまな中古製品を見ることができます.これらの製品は中古品ですが、商品の品質には全く問題はございませんので、どなたでも安心してご購入いただけますし、価格も非常にお手頃でありながら、どなたでも気軽に商品を手に取ることができます。コミュニケーションをとり、価格交渉を行います。全員が適切に交渉している限り、取引を行うことを選択できます。ここで全員が支払いをするときに、WeChat 支払いをしたいのですが、プラットフォームでは許可されていないようです。編集者をフォローしてください。具体的にどのような状況なのかを知るためです。項羽

Alibaba 1688 は仕入れと卸売りのサイトで、商品の価格はタオバオよりもはるかに安いです。では、アリババはどのようにして WeChat 決済を利用しているのでしょうか?編集者は、あなたと共有するためにいくつかの関連コンテンツをまとめました。必要としている友人は、見に来てください。アリババはどのように WeChat 決済を使用していますか? 回答: 当面の間、WeChat 決済はご利用いただけません; 1. 商品を購入するページで [支払い方法の変更] をクリックします。 2. ポップアップ ページで [支払い方法の変更] をクリックするだけです。 [Alipay、段階的支払い]、レジ係] を選択できます。

1. まず、携帯電話で WeChat アプリを開き、クリックして WeChat アカウントにログインし、WeChat ホームページに入ります。 2. WeChat ホームページの右下隅にある [自分] ボタンをクリックし、[支払い] オプションを選択して、支払いページに入ります。 3. [Payment] ページに入ったら、[Wallet] オプションをクリックして入り、[Wallet] ページの右上隅にある [Bill] をクリックします。

WeChat 支払いは、支払いが成功した後すぐにキャンセルすることはできません。返金は通常、次の条件を満たす必要があります: 1. 販売者の返金ポリシー 販売者は、返金期間、返金金額、返金方法を含む独自の返金ポリシーを策定します; 2. 支払時期、返金には通常、一定の期間内に適用する必要があります。 3. 商品またはサービスのステータス ユーザーが商品を受け取った、またはサービスを享受した場合、販売者はユーザーに商品の返品または対応する証拠の提出を要求する場合があります。プロセスなど

Didi Chuxing アプリは、誰もが毎日の旅行をさらに便利にします。どこにでも行きたいところに行くことができ、すべての Didi 車両が待機しています。心配して待つ必要はもうありません。何十ものタクシー用赤い封筒が無料で入手できます。より速く移動できます。ソフトウェアのホームページを開き、個人の旅程に従って出発地と目的地を入力し、以下のさまざまな価格の車両から自由に選択してください。ワンクリックで注文し、旅程を公開してください。Didi ドライバーは数秒で注文を受け取り、到着します。指定された場所にできるだけ早く到着します 場所は、バスに乗る前に携帯電話番号を確認するだけです もちろん、運賃の支払い方法は WeChat や Alipay などたくさんありますが、通常は誰もが WeChat を使用します。ワンクリックで支払いを簡単に設定できます。編集者はオンラインで 1 つずつ注意深く滴滴の支払いを行っています。旅行ユーザーが WeChat 支払いの設定方法を紹介しています。 1. 私たちは携帯電話を使っています
