目录

关于微信支付接口V2版本

如何配置APIv2密钥

配置Native支付回调链接

微信返回的数据

回调业务实现

获取微信返回的数据

反馈微信服务器

业务程序处理

小结

关于微信支付接口V2版本

使用微信支付接口V2版本开发微信支付,这里我们以JSAPI为例,其将使用APIv2密钥,该密钥是指调用微信支付API时,要按照指定规则对请求数据进行签名。服务器收到调用请求后会进行签名验证,需用APIv2密钥生成签名,从而界定商户的身份并防止他人恶意篡改数据。签名的计算规则中,使用到的key就是APIv2密钥。

如何配置APIv2密钥

 登录微信支付商家平台:微信支付 - 中国领先的第三方支付平台 | 微信支付提供安全快捷的支付方式

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

配置Native支付回调链接

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

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

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

微信返回的数据

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

1

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

回调业务实现

获取微信返回的数据

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数据则表示通知微信服务器处理成功:

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

private string PostResult(bool success, string failMessage)

{

if (success) failMessage = "";

//SUCCESS/FAIL

string result = "" +

"" +

" " +

" " +

"";

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);

    }

}//pageload

小结

 1、拼接的字符串格式如下示例:

appid=wx64&attach=0.01&bank_type=OTHERS&cash_fee=1&fee_type=CNY&is_subscribe=N&mch_id=163&nonce_str=34173&openid=ou4Rz&out_trade_no=5f26&result_code=SUCCESS&return_code=SUCCESS&time_end=2024&total_fee=1&trade_type=JSAPI&transaction_id=42000021&key=APIv2

我们在开发调试中务必遵循关键字及值的拼接顺序

2、示例代码中的 dal类实现了对数据库的操作,是自研发的组件,我们需要根据实际的业务进行自行定义与开发。

3、后台通知反馈微信服务器时,如果微信收到商户的应答不符合规范或超时,微信会判定本次通知失败,重新发送通知,直到成功为止,通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m),但微信不保证通知最终一定能成功。

4、为完善系统功能,建议进一步开发查询订单对帐功能,并成功更新确认订单状态。

以上是本人的一些体会与实践,再次感谢您的阅读,欢迎讨论、指教!

推荐链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: