微信原生支付 Native掃碼支付( V3.3.7 版本)

原文:微信原生支付 Native掃碼支付( V3.3.7 版本)php

[尊重別人的勞動成果,轉載請註明出處:一縷晨光工做室,www.wispdawn.com]html

前言算法

辛苦研究三天,遇到各類困難,最終仍是克服了,把個人理解和思路分享給須要幫助的人,若是你覺的好,請幫我分享一下,謝謝。 在沒有作以前,我覺得和支付寶,以及銀聯同樣,會在官網找到相應的demo,照葫蘆畫瓢便可,沒有什麼複雜的,真正去作的時候,發現各類錯誤,不少時候都莫名其妙找不到北, 在網上搜了不知道多少遍,有V3版的,不過都是js api版本的,沒有找到原生掃碼支付,下了幾個V2版本的微信支付c#demo,感受亂糟糟的。官網只提供了一個php版本的demo 研究了一天沒有結果,次日我決定從官網的php的原生掃碼支付,根據他的邏輯,用c#寫出來,下面就是全部思路及代碼,文章最後我放上整個解決方案壓縮包。數據庫

想實現掃碼支付須要三大步驟c#

  1. 生成二維碼,二維碼包含產品ID
  2. 微信公衆平臺->微信支付->配置支付回調URL(本身開發回調頁面)
  3. 開發支付成功後通知頁面

最終效果如圖api

下面一步一步講解數組

一.生成二維碼

 這步驟比較簡單,根據官網文檔 ,須要固定的參數,其中籤名算法已經寫好,以下代碼微信

下圖是用於生成二維碼字符串,app

public string CreateQRCodeUrl(string productid)
  {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            dic.Add("appid", helper.GetAppId);
            dic.Add("mch_id", helper.GetMch_Id);
            dic.Add("nonce_str", TenpayUtil.getNoncestr());
            dic.Add("product_id", productid);
            dic.Add("time_stamp", TenpayUtil.getTimestamp());
            dic.Add("sign",helper.GetSign(dic));
           
            string url = WxPayHelper.FormatBizQueryParaMap(dic, false);//這裏不要url編碼
            return "weixin://wxpay/bizpayurl?" + url;
 }
生成微信二維碼字符串

 

最終生成的url微信公衆平臺

weixin://wxpay/bizpayurl?appid=wxed94e****9b4bc&mch_id=122468****&nonce_str=877A9BA7A98F75B90A9D49F53F15A858& product_id=1&sign=B2A03B1B6583972FF67C8AD3D7414DD1&time_stamp=1420466744

有了文本想生成二維碼就簡單了,起初我是採用ThoughtWorks.QRCode.dll,後來發現一值報錯,超出數組範圍,估計是字符串太長了,最後選擇使用一個開源項目 Gma.QrCodeNet.Encoding.dll,速度很快。

代碼以下

 WxPayHelper helper = new WxPayHelper();
        public void ProcessRequest(HttpContext context)
        {         
            if (context.Request["buynum"]!=null)
            {
                string proId ="1";//示例代碼寫死了,本身根據業務處理
                string qrurl = CreateQRCodeUrl(proId);

                QrEncoder qrEncoder = new QrEncoder(ErrorCorrectionLevel.H);
                Gma.QrCodeNet.Encoding.QrCode qrCode = new Gma.QrCodeNet.Encoding.QrCode();
                qrEncoder.TryEncode(qrurl, out qrCode);
                using (MemoryStream ms = new MemoryStream())
                {
                    var renderer = new GraphicsRenderer(new FixedModuleSize(4, QuietZoneModules.Two));
                    renderer.WriteToStream(qrCode.Matrix, ImageFormat.Png, ms);
                    context.Response.ContentType = "image/png";
                    context.Response.OutputStream.Write(ms.GetBuffer(), 0, (int)ms.Length);
                }
            }          
        }
生成二維碼

 

前臺js調用

$(function () {
            $("#txtKey").keyup(function () {               
                var num=$(this).val();//這裏設置購買數量
                $("#qrDiv").html("<img src=QrCode.ashx?buynum="+num+" height=200 width=200 /> ");
            });
 });

 

2、寫回調頁面,本程序是NativeCallBack.aspx

這個頁面主要任務是當掃碼二維碼的時候,微信向這個頁面post XML數據,其中包含產品id,即二維碼上的產品id ,咱們須要根據產品id,查詢產品名稱,總價格,以及一些附屬信息, 咱們須要再次把這些參數post給微信統一支付接口,若是數據正確,微信會給咱們生成一個prepay_id 預支付id,咱們再次把prepay_id post給微信,整個流程便是這樣子的,其實產品id就至關於一個訂單號,惟一性,固然你也能夠根據產品id,在這個頁面裏面下單,業務根據本身須要處理。

頁面代碼以下

log4net.ILog logger = WxV3.Helper.LogHelper.GetInstance().Log;
        WxV3.Helper.WxPayHelper helper = new Helper.WxPayHelper();
        protected void Page_Load(object sender, EventArgs e)
        {
            //1.接受微信平臺post 過來的XML信息
            //2.驗證簽名,從XML中獲取ProductID,獲取產品信息
            //2.1設置out_trade_no,total_fee,notify_url,trade_type,product_id 參數,提交統一接口         
            //3.提交統一接口後獲取PrepayId
            //4.將PrepayId 和return 根據參數拼接生xml信息(其中包含生成的package參數)輸出
            if (Request.RequestType == "POST")
            {
                try
                {
                    StreamReader reader = new StreamReader(Request.InputStream);
                    String xmlData = reader.ReadToEnd();
                    helper.ReceivePostXmlData(xmlData);
                    logger.Info("接收post來的xmlData=" + xmlData);
                    if (helper.CheckSign())
                    {
                        logger.Info("簽名驗證經過");
                        string proId = helper.GetProductId();
                        logger.Info("產品id=" + proId);

                        switch (proId)
                        {
                            case "1":
                               
                                #region 業務處理
                                helper.SetParameter("body", "一縷晨光CMS系統");
                                helper.SetParameter("out_trade_no", DateTime.Now.ToString("yyyyMMddHHmmss") + CommonUtil.BuildRandomStr(4));
                                helper.SetParameter("total_fee", "88800");//這裏單位是分
                                helper.SetParameter("notify_url", "http://www.wispdawn.com/WxV3/NativeNotify.aspx");
                                helper.SetParameter("trade_type", "NATIVE");
                                string prepay_id = helper.GetPrepayId();
                                logger.Info("prepay_id=" + prepay_id);
                                if (!string.IsNullOrEmpty(prepay_id))
                                {
                                    helper.SetReturnParameter("return_code", "SUCCESS");
                                    helper.SetReturnParameter("result_code", "SUCCESS");
                                    helper.SetReturnParameter("prepay_id", prepay_id);
                                    helper.SetReturnParameter("appid", helper.GetAppId);
                                    helper.SetReturnParameter("mch_id", helper.GetMch_Id);
                                    helper.SetReturnParameter("nonce_str", TenpayUtil.getNoncestr());
                                }
                                else
                                {
                                    helper.SetReturnParameter("return_code", "SUCCESS");//返回狀態碼
                                    helper.SetReturnParameter("result_code", "FAIL");//業務結果
                                    helper.SetReturnParameter("err_code_des", "預訂單生產失敗");
                                }
                                #endregion

                                break;
                            default:
                                helper.SetReturnParameter("return_code", "SUCCESS");//返回狀態碼
                                helper.SetReturnParameter("result_code", "FAIL");//業務結果
                                helper.SetReturnParameter("err_code_des", "此商品無效");//業務結果
                                break;
                        }
                    }
                    else
                    {
                        helper.SetReturnParameter("return_code", "FAIL");
                        helper.SetReturnParameter("return_msg", "簽名失敗");
                        logger.Info("簽名驗證沒有經過");
                    }
                    string xmlStr = helper.GetReturnXml();
                    logger.Info("返回xml=" + xmlStr);
                    Response.ContentType = "text/xml";
                    Response.Clear();
                    Response.Write(xmlStr);
                    Response.End();
                }
                catch (Exception ex)
                {
                    logger.Error("異常了", ex);
                }
            }
        }
NativeCallBack代碼

 

3、支付通知頁面,本程序 NativeNotify.aspx

這個頁面用來處理成功通知的,微信把交易的結果依xml形式post該頁面,當你收到消息後,若是成功了,你能夠根據此來修改數據庫,或者更新狀態,等等。我作到這步時候,須要實現掃碼二維碼,支付成功後,3秒後調整, 實現思路是這樣的,在二維碼頁面,setinterval get後臺數據庫是否已經支付,若是已經支付則執行settimeout 3秒後調整到成功頁面。目前我是這樣實現的,不知作別人怎麼實現的。

通知代碼以下。

  log4net.ILog logger = WxV3.Helper.LogHelper.GetInstance().Log;
        WxV3.Helper.WxPayHelper helper = new Helper.WxPayHelper();
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Request.RequestType == "POST")
            {
                try
                {
                    StreamReader reader = new StreamReader(Request.InputStream);
                    String xmlData = reader.ReadToEnd();
                    helper.ReceivePostXmlData(xmlData);
                    logger.Info("Notify_接收post來的xmlData=" + xmlData);
                    if (helper.CheckSign())
                    {
                        Dictionary<string, string> dicBack = helper.GetParameter();//獲取全部參數
                        if (dicBack!=null&&dicBack.Keys.Contains("return_code"))
                        {
                            if (dicBack["return_code"] == "SUCCESS")
                            {
                                logger.Info("return_code=SUCCESS");
                                if (dicBack["result_code"]=="SUCCESS")
                                {
                                    logger.Info("result_code=SUCCESS");                                  
                                    string out_trade_no = dicBack["out_trade_no"];//商戶訂單號
                                    logger.Info("out_trade_no="+out_trade_no);

                                    //1.驗證商戶訂單號是否被處理
                                    //2.處理過直接返回成功,不然返回
                                    //此處根據out_trade_no 處理業務數據


                                    //處理業務數據結束

                                    logger.Info("Notify_驗證簽名成功");
                                    helper.SetReturnParameter("return_code", "SUCCESS");
                                    helper.SetReturnParameter("return_msg", "");   
                                }    
                            }
                            if (dicBack["return_code"]=="FAIL")
                            {
                                logger.Info("Notify_驗證簽名成功");
                                helper.SetReturnParameter("return_code", "SUCCESS");
                                helper.SetReturnParameter("return_msg", dicBack["return_msg"]);    
                            }
                        }
                    }
                    else
                    {
                        logger.Info("Notify_驗證簽名失敗");
                        helper.SetReturnParameter("return_code", "FAIL");
                        helper.SetReturnParameter("return_msg", "簽名失敗");     
                    }
                    string xmlStr = helper.GetReturnXml();
                    logger.Info("Notify_返回xml=" + xmlStr);
                    Response.ContentType = "text/xml";
                    Response.Clear();
                    Response.Write(xmlStr);
                    Response.End();
                }
                catch (Exception ex)
                {
                    logger.Error("Notify_異常了", ex);
                }
            }
        }
NativeNotify頁面代碼

 

若是你也是須要掃描原生支付,能夠直接下載本解決方案,只須要把 WxPayHelper構造函數中的參數修改下便可使用

 public WxPayHelper()
        {
            this.parameters = new Dictionary<string, string>();
            this.returnParameter = new Dictionary<string, string>();
            this.appid = "wxed94e6985d29****";//appid
            this.mch_id = "122468****";      //微信支付商戶號         
            this.PartnerKey = "ASD2Ssaghh3df4570erdssd4we33****";//這裏是商戶的partnerkey  
        }

 

本文主要講解整個思路,詳細請看代碼,點擊下載本解決方案

尊重別人的勞動成功,轉載請註明出處:一縷晨光工做室,www.wispdawn.com

相關文章
相關標籤/搜索