微信支付(公衆號支付)ASP.NET

微信公衆號支付官方文檔


目錄:


場景介紹
商戶已有H5商城網站,用戶通過消息或掃描二維碼在微信內打開網頁時,可以調用微信支付完成下單購買的流程。

步驟(1):

商戶下發圖文消息或者通過自定義菜單吸引用戶點擊進入商戶網頁(商戶網頁下單)。

步驟(2):

進入商戶網頁,用戶選擇購買,完成選購流程(請求微信支付)。

這裏寫圖片描述

步驟(3):

調起微信支付控件,用戶開始輸入支付密碼。

步驟(4):

密碼驗證通過,支付成功。商戶後臺得到支付成功的通知。

這裏寫圖片描述

步驟(5):

返回商戶頁面,顯示購買成功。該頁面由商戶自定義。

步驟(6):

微信支付公衆號下發支付憑證。

步驟(7):

商戶公衆號下發消息,提示發貨成功。該步驟可選。

這裏寫圖片描述

注意:商戶也可以把商品網頁的鏈接生成二維碼,用戶掃一掃打開後即可完成購買支付。

交互細節:

以下是支付場景的交互細節,請認真閱讀,設計商戶頁面的邏輯:
(1)用戶打開商戶網頁選購商品,發起支付,在網頁通過JavaScript調用getBrandWCPayRequest接口,發起微信支付請求,用戶進入支付流程。
(2)用戶成功支付點擊完成按鈕後,商戶的前端會收到JavaScript的返回值。商戶可直接跳轉到支付成功的靜態頁面進行展示。
(3)商戶後臺收到來自微信開放平臺的支付成功回調通知,標誌該筆訂單支付成功。
注:(2)和(3)的觸發不保證遵循嚴格的時序。JS API返回值作爲觸發商戶網頁跳轉的標誌,但商戶後臺應該只在收到微信後臺的支付成功回調通知後,才做真正的支付成功的處理。

官方流程圖

這裏寫圖片描述

簡單流程圖:

Created with Raphaël 2.1.0開始用戶打開公衆號內的鏈接選擇購買產品觸發按鈕發起支付進行一次AJAX請求,將數據提交到後臺提交成功?轉到支付頁面支付頁面通過JavaScript調用getBrandWCPayRequest接口,發起支付,用戶輸入支付密碼支付成功?密碼驗證通過,提示支付成功。點擊完成按鈕,商戶前端getBrandWCPayRequest接口的回調函數內會收到支付成功返回參數因爲微信團隊鄭重提示:res.err_msg將在用戶支付成功後返回ok,但並不保證它絕對可靠。所以我們進行一次AJAX請求一般處理程序,使用微信訂單號,調用查詢訂單接口,保證此訂單真正交易成功真正成功?轉到自定義成功提示頁面諮詢微信官方不通過,微信自身提示密碼錯誤yesnoyesnoyesno

代碼:

商品選擇頁面 Product.aspx

        function checkForm() {
            var d = document, n, c, validn, validc, obj = {}, mobile = /^1[3|4|5|8|7][0-9]\d{4,8}$/;
            n = d.getElementById('tbcarnum').value;
            c = d.getElementById('tbcontact').value;
            validn = d.getElementById('validnum');
            validc = d.getElementById('validcon');
            if (n === '') { validn.innerHTML = '必填'; return false; }
            else { validn.innerHTML = ''; }
            if (c === '') { validc.innerHTML = '必填'; return false; }
            else { validc.innerHTML = ''; }
            if (c.length != 11 || !mobile.test(c)) {
                validc.innerHTML = '聯繫方式格式不正確'; return false;
            }
            else { validc.innerHTML = ''; }
            //go
            obj.num = n;
            obj.con = c;
            obj.type = document.getElementById('hid').value;
            //創建訂單
            $.post("ashx/CreateOrder.ashx", obj, function (data) {
                var json = JSON.parse(data);
                if (json.code === 200) {//成功則轉到支付頁面
                    location.href = "paypage.aspx";
                } else {
                    alert('提交失敗');
                }
            });
        }

支付頁面 PayPage

網頁授權獲取過程

微信網頁授權

以下代碼DEMO 內是有的,在此我只是做了略微修改

SDK與DEMO下載

實例化 JsApiPay 類,需要一個 web 窗體作爲參數。

PayPage.cs

        public string jsapiparms = "";
        public string wxorder = "";
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                JsApiPay payObj = new JsApiPay(this);
                // 網頁授權獲取
                payObj.GetOpenidAndAccessToken();
                //統一下單
                WxPayData order = payObj.GetUnifiedOrderResult();
                //微信商戶訂單號
                wxorder = payObj.wx_ordernum;
                //jsapi支付所需的參數
                jsapiparms = payObj.GetJsApiParameters();
            }
        }

PayPage.aspx

    <script type="text/javascript">
        function onBridgeReady() {
            WeixinJSBridge.invoke('getBrandWCPayRequest', <%=jsapiparms %>, function (res) {
                 if (res.err_msg == "get_brand_wcpay_request:ok") {
                    <!--調起查詢訂單接口,查詢訂單是否真正交易成功-->
                    $.post('ashx/CheckOrderStatus.ashx',{onum:'<%=wxorder %>'},function(data){
                        var json=JSON.parse(data);
                        if(json.code===200){
                            document.getElementById('status').innerHTML=json.res;
                        }else{
                            alert(json.res);
                        }
                        // 轉到自定義成功頁面
                        window.location.href=json.url;
                    });
                 }     // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返回    ok,但並不保證它絕對可靠。 
             });
        }
        if (typeof WeixinJSBridge == "undefined") {
            if (document.addEventListener) {
                document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
            } else if (document.attachEvent) {
                document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
                document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
            }
        } else {
            onBridgeReady();
        }
    </script>
  • 第一步:利用url跳轉獲取code
        /**
        * 
        * 網頁授權獲取用戶基本信息的全部過程
        * 詳情請參看網頁授權獲取用戶基本信息: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);
                // 利用code去獲取openid和access_token 
                GetOpenidAndAccessTokenFromCode(code);
            }
            else
            {
                //構造網頁授權獲取code的URL
                string host = page.Request.Url.Host;
                string path = page.Request.Path;
                string redirect_uri = HttpUtility.UrlEncode("http://" + host + path);
                WxPayData data = new WxPayData();
                data.SetValue("appid", WxPayConfig.APPID);
                Log.Info("redirect_url:", redirect_uri);
                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去獲取openid和access_token
        /**
        * 
        * 通過code換取網頁授權access_token和openid的返回數據,正確時返回的JSON數據包如下:
        * {
        *  "access_token":"ACCESS_TOKEN",
        *  "expires_in":7200,
        *  "refresh_token":"REFRESH_TOKEN",
        *  "openid":"OPENID",
        *  "scope":"SCOPE",
        *  "unionid": "xxxxxxxxxxxxxxxxxxxxxxxxx"
        * }
        * 其中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(string proname)
        {
            //統一下單
            WxPayData data = new WxPayData();
            data.SetValue("body", proname);
            data.SetValue("attach", proname);
            string order = WxPayApi.GenerateOutTradeNo();
            data.SetValue("out_trade_no", order);
            //自定義屬性,保存微信訂單號
            wx_ordernum = order;
            Log.Info("order", order);

            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", proname);
            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支付所需的參數,
        * 微信瀏覽器調起JSAPI時的輸入參數格式如下:
        * {
        *   "appId" : "wxxxxxxxxxxxxxxxxxx",     //公衆號名稱,由商戶傳入     
        *   "timeStamp":"1395712654",         //時間戳,自1970年以來的秒數     
        *   "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //隨機串     
        *   "package" : "prepay_id=xxxxxxxxxxxxxxxxxxxx",     
        *   "signType" : "MD5",         //微信簽名方式:    
        *   "paySign" : "xxxxxxxxxxxxxxxxxxxxx" //微信簽名 
        * }
        * @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;
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章