Advertisement

C# 微信支付接口V2版本回调开发实践

阅读量:

进入平台后,如下图选择帐户中心、API安全,如果没有申请API证书请申请(退款时需要使用证书),下面就是配置APIv2密钥,我们可以选择创建或修改,配置过程需要提供操作员的密码和手机认证短信。

配置Native支付回调链接

如下图进入产品中心、开发配置。

滚动界面至支付配置、Native支付回调链接,如下图所示:

点击添加或修改链接,强烈建议选择 HTTPS://,后面则填写我们处理回调的程序 URL 地址,配置过程需要提供操作员的密码和手机认证短信。

微信返回的数据

V2版本在微信支付成功后,POST返回给回调地址的数据格式为XML,其样例如下:

复制代码
    <xml><appid><![CDATA[wx64]]></appid>
    <attach><![CDATA[0.01]]></attach>
    <bank_type><![CDATA[OTHERS]]></bank_type>
    <cash_fee><![CDATA[1]]></cash_fee>
    <fee_type><![CDATA[CNY]]></fee_type>
    <is_subscribe><![CDATA[N]]></is_subscribe>
    <mch_id><![CDATA[163]]></mch_id>
    <nonce_str><![CDATA[34173]]></nonce_str>
    <openid><![CDATA[ou4Rz6qfCP]]></openid>
    <out_trade_no><![CDATA[5f26]]></out_trade_no>
    <result_code><![CDATA[SUCCESS]]></result_code>
    <return_code><![CDATA[SUCCESS]]></return_code>
    <sign><![CDATA[5C4A6D72C485]]></sign>
    <time_end><![CDATA[20240408111541]]></time_end>
    <total_fee>1</total_fee>
    <trade_type><![CDATA[JSAPI]]></trade_type>
    <transaction_id><![CDATA[4200002165]]></transaction_id>
    </xml>
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    

因此我们需要根据返回的数据进行后续业务处理,包括签名验证。

回调业务实现

获取微信返回的数据

GetPostContent方法用于微信支付成功后,接收微信POST过来的回调数据,示例代码如下:

复制代码
    private string GetPostContent()
    {
        Int32 intLength = Convert.ToInt32(Request.InputStream.Length);
        byte[] con = new byte[intLength];
        Request.InputStream.Read(con, 0, intLength);
        return System.Text.Encoding.UTF8.GetString(con);
    }
    
    
      
      
      
      
      
      
      
    
反馈微信服务器

处理程序的最终结果需要反馈给微信服务器,反馈以下XML数据则表示通知微信服务器处理成功:

复制代码
    <xml> 
     <return_code><![CDATA[SUCCESS]]></return_code>
     <return_msg><![CDATA[OK]]></return_msg>
    </xml>
    
    
      
      
      
      
    

除以上信息外的任何反馈,微信服务器则会定时轮询处理。以下代码为反馈程序,该程序指定了PostResult方法:

复制代码
    private string PostResult(bool success, string failMessage)
    {
        if (success) failMessage = "";
    
        //SUCCESS/FAIL
        string result = "" +
       "<xml>" +
       " <return_code><![CDATA[" + (success ? "SUCCESS" : "FAIL") + "]]></return_code>" +
       " <return_msg><![CDATA[" + (success ? "OK" : failMessage) + "]]></return_msg>" +
       "</xml>";
        return result;
    }
    
    
      
      
      
      
      
      
      
      
      
      
      
      
    
业务程序处理

设计流程基本思路如下:

1、获取微信POST过来的XML,判断return_code是否为SUCCESS

2、解析XML,根据字段进行签名字串的拼接

3、使用APIv2密钥对签名字串继续拼接并生成大写的MD5字符串,与POST的XML中的sign字段值进行比较以验证

4、验证成功则处理自己的业务程序,并反馈给微信服务器数据

核心代码如下:

复制代码
    protected void Page_Load(object sender, EventArgs e)  
    {
        try
          {
             String xmlData = GetPostContent();//获取请求数据
    
        
            if (String.IsNullOrWhiteSpace(xmlData))
            {
              this.Response.Write("未接受到微信回调数据。");//返回微信服务器
               return;
            }
        
            //把数据重新返回给客户端
             DataSet ds = new DataSet();
            StringReader stram = new StringReader(xmlData);
            XmlTextReader datareader = new XmlTextReader(stram);
            ds.ReadXml(datareader);
            if (ds.Tables[0].Rows[0]["return_code"].ToString() == "SUCCESS")
            {
               string wx_appid = "";
                            string wx_attach = "";
               string wx_mch_id = "";
               string wx_nonce_str = "";
               string wx_sign = "";
               string wx_result_code = "";//SUCCESS/FAIL
               string wx_return_code = "";
               string wx_openid = "";
               string wx_is_subscribe = "";
               string wx_trade_type = "";
               string wx_bank_type = "";
               string wx_fee_type = "";
               string wx_transaction_id = "";
               string wx_out_trade_no = "";
               string wx_time_end = "";
               int wx_total_fee = -1;
               int wx_cash_fee = -1;
          
               string signstr = "";//需要拼接的字符串
          
              //wx_appid
               if (ds.Tables[0].Columns.Contains("appid"))
              {
                wx_appid = ds.Tables[0].Rows[0]["appid"].ToString();
                if (!string.IsNullOrEmpty(wx_appid))
                {
                  signstr += "appid=" + wx_appid;
                }
              }
           //wx_attach
                 if (ds.Tables[0].Columns.Contains("attach"))
              {
                  wx_attach = ds.Tables[0].Rows[0]["attach"].ToString();
                  if (!string.IsNullOrEmpty(wx_attach))
                {
                signstr += "&attach=" + wx_attach;
                }
              }
          
              //wx_bank_type
               if (ds.Tables[0].Columns.Contains("bank_type"))
              {
                wx_bank_type = ds.Tables[0].Rows[0]["bank_type"].ToString();
                if (!string.IsNullOrEmpty(wx_bank_type))
                {
                  signstr += "&bank_type=" + wx_bank_type;
                }
              }
              //wx_cash_fee
               if (ds.Tables[0].Columns.Contains("cash_fee"))
              {
                wx_cash_fee = Convert.ToInt32(ds.Tables[0].Rows[0]["cash_fee"].ToString());
            
                signstr += "&cash_fee=" + wx_cash_fee;
              }
          
              //wx_fee_type
               if (ds.Tables[0].Columns.Contains("fee_type"))
              {
                wx_fee_type = ds.Tables[0].Rows[0]["fee_type"].ToString();
                if (!string.IsNullOrEmpty(wx_fee_type))
                {
                  signstr += "&fee_type=" + wx_fee_type;
                }
              }
          
              //wx_is_subscribe
               if (ds.Tables[0].Columns.Contains("is_subscribe"))
              {
                wx_is_subscribe = ds.Tables[0].Rows[0]["is_subscribe"].ToString();
                if (!string.IsNullOrEmpty(wx_is_subscribe))
                {
                  signstr += "&is_subscribe=" + wx_is_subscribe;
                }
              }
          
              //wx_mch_id
               if (ds.Tables[0].Columns.Contains("mch_id"))
              {
                wx_mch_id = ds.Tables[0].Rows[0]["mch_id"].ToString();
                if (!string.IsNullOrEmpty(wx_mch_id))
                {
                  signstr += "&mch_id=" + wx_mch_id;
                }
              }
          
              //wx_nonce_str
               if (ds.Tables[0].Columns.Contains("nonce_str"))
              {
                wx_nonce_str = ds.Tables[0].Rows[0]["nonce_str"].ToString();
                if (!string.IsNullOrEmpty(wx_nonce_str))
                {
                  signstr += "&nonce_str=" + wx_nonce_str;
                }
              }
          
              //wx_openid
               if (ds.Tables[0].Columns.Contains("openid"))
              {
                wx_openid = ds.Tables[0].Rows[0]["openid"].ToString();
                if (!string.IsNullOrEmpty(wx_openid))
                {
                  signstr += "&openid=" + wx_openid;
                }
              }
          
              //wx_out_trade_no
               if (ds.Tables[0].Columns.Contains("out_trade_no"))
              {
                wx_out_trade_no = ds.Tables[0].Rows[0]["out_trade_no"].ToString();
                if (!string.IsNullOrEmpty(wx_out_trade_no))
                {
                  signstr += "&out_trade_no=" + wx_out_trade_no;
                }
              }
          
              //wx_result_code
               if (ds.Tables[0].Columns.Contains("result_code"))
              {
                wx_result_code = ds.Tables[0].Rows[0]["result_code"].ToString();
                if (!string.IsNullOrEmpty(wx_result_code))
                {
                  signstr += "&result_code=" + wx_result_code;
                }
              }
          
              //wx_return_code
               if (ds.Tables[0].Columns.Contains("return_code"))
              {
                wx_return_code = ds.Tables[0].Rows[0]["return_code"].ToString();
                if (!string.IsNullOrEmpty(wx_return_code))
                {
                  signstr += "&return_code=" + wx_return_code;
                }
              }
          
              //wx_sign
               if (ds.Tables[0].Columns.Contains("sign"))
              {
                wx_sign = ds.Tables[0].Rows[0]["sign"].ToString();
              }
          
              //wx_time_end
               if (ds.Tables[0].Columns.Contains("time_end"))
              {
                wx_time_end = ds.Tables[0].Rows[0]["time_end"].ToString();
                if (!string.IsNullOrEmpty(wx_time_end))
                {
                  signstr += "&time_end=" + wx_time_end;
                }
              }
          
              //wx_total_fee
               if (ds.Tables[0].Columns.Contains("total_fee"))
              {
                wx_total_fee = Convert.ToInt32(ds.Tables[0].Rows[0]["total_fee"].ToString());
            
                signstr += "&total_fee=" + wx_total_fee;
              }
          
              //wx_trade_type
               if (ds.Tables[0].Columns.Contains("trade_type"))
              {
                wx_trade_type = ds.Tables[0].Rows[0]["trade_type"].ToString();
                if (!string.IsNullOrEmpty(wx_trade_type))
                {
                  signstr += "&trade_type=" + wx_trade_type;
                }
              }
          
              //wx_transaction_id
               if (ds.Tables[0].Columns.Contains("transaction_id"))
              {
                wx_transaction_id = ds.Tables[0].Rows[0]["transaction_id"].ToString();
                if (!string.IsNullOrEmpty(wx_transaction_id))
                {
                  signstr += "&transaction_id=" + wx_transaction_id;
                }
              }
          
          
              //追加key APIv2密钥
               signstr += "&key=" + System.Web.Configuration.WebConfigurationManager.AppSettings["APIv2"].ToString();
    
           dal.ErrorMessage = "";
           dal.RowsCount = 0;
           dal.ConnKeyString = "JaneConnection_enroll";
           ArrayList paras = new ArrayList();
           paras.Clear();
           paras.Add(new SqlParameter("orderid", wx_out_trade_no));
           object rv = dal.GetDataSet("select cid from  dlzp_ypz  where wxPreOrdId=@orderid", paras);
           if (dal.ErrorMessage != "" || dal.RowsCount != 1)
           {
               this.Response.Write(this.PostResult(false, "定位用户ID错误!" + wx_out_trade_no));//返回微信服务器
               return;
           }
           DataSet dsper = rv as DataSet;
    
           string ypz_cid = dsper.Tables[0].Rows[0]["cid"].ToString();
           string err_msg = "";
           if (wx_result_code == "SUCCESS")
           {
               err_msg = "get_brand_wcpay_request:ok";
           }
    
    
              string md5 = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(signstr, "MD5").ToUpper();
          
              //签名验证成功
              if (wx_sign == md5)
              {
                //签名正确,更新数据库订单状态
                      paras.Clear();
                      paras.Add(new SqlParameter("ypz_cid", ypz_cid));
                      paras.Add(new SqlParameter("mch_id", wx_mch_id));
                      paras.Add(new SqlParameter("openid", wx_openid));
                      paras.Add(new SqlParameter("orderid", wx_out_trade_no));
                      paras.Add(new SqlParameter("err_msg", err_msg));
                      dal.ExecDbScripts("ar_wx_updUserPayInfo", paras, CommandType.StoredProcedure);
                      if (dal.ErrorMessage != "" || dal.RowsCount == 0)
                      {
                          this.Response.Write(this.PostResult(false, "更新支付状态失败!"));//返回微信服务器
                          return;
                      }
                this.Response.Write(this.PostResult(true, ""));//返回微信服务器成功信息
    
               }
              else
              {
    		                    this.Response.Write(this.PostResult(false, "签名错误!"));//返回微信服务器
               }
          }
          else
          {
                    this.Response.Write(this.PostResult(false, "微信接口返回FAIL"));//返回微信服务器
           }
          }//SUCCESS
           catch (Exception ex)
           {
             this.Response.Write(ex.Message);
           }
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    

全部评论 (0)

还没有任何评论哟~