后台配置接入微信支付回调:
附上微信接口API统一支付文档:
返回结果
字段名 | 变量名 | 必填 | 类型 | 示例值 | 描述 |
---|---|---|---|---|---|
返回状态码 | return_code | 是 | String(16) | SUCCESS | SUCCESS/FAIL 此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断 |
返回信息 | return_msg | 是 | String(128) | OK | 当return_code为FAIL时返回信息为错误原因 ,例如 签名失败 参数格式校验错误 |
以下字段在return_code为SUCCESS的时候有返回
字段名 | 变量名 | 必填 | 类型 | 示例值 | 描述 |
---|---|---|---|---|---|
公众账号ID | appid | 是 | String(32) | wx8888888888888888 | 调用接口提交的公众账号ID |
商户号 | mch_id | 是 | String(32) | 1900000109 | 调用接口提交的商户号 |
设备号 | device_info | 否 | String(32) | 013467007045764 | 自定义参数,可以为请求支付的终端设备号等 |
随机字符串 | nonce_str | 是 | String(32) | 5K8264ILTKCH16CQ2502SI8ZNMTM67VS | 微信返回的随机字符串 |
签名 | sign | 是 | String(32) | C380BEC2BFD727A4B6845133519F3AD6 | 微信返回的签名值,详见签名算法 |
业务结果 | result_code | 是 | String(16) | SUCCESS | SUCCESS/FAIL |
错误代码 | err_code | 否 | String(32) | 当result_code为FAIL时返回错误代码,详细参见下文错误列表 | |
错误代码描述 | err_code_des | 否 | String(128) | 当result_code为FAIL时返回错误描述,详细参见下文错误列表 |
以下字段在return_code 和result_code都为SUCCESS的时候有返回
字段名 | 变量名 | 必填 | 类型 | 示例值 | 描述 |
---|---|---|---|---|---|
交易类型 | trade_type | 是 | String(16) | JSAPI | JSAPI 公众号支付 NATIVE 扫码支付 APP APP支付 说明详见参数规定 |
预支付交易会话标识 | prepay_id | 是 | String(64) | wx201410272009395522657a690389285100 | 微信生成的预支付会话标识,用于后续接口调用中使用,该值有效期为2小时 |
二维码链接 | code_url | 否 | String(64) | URl:weixin://wxpay/s/An4baqw | trade_type为NATIVE时有返回,用于生成二维码,展示给用户进行扫码支付 |
举例如下:
<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wx2421b1c4370ec43b]]></appid>
<mch_id><![CDATA[10000100]]></mch_id>
<nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str>
<openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid>
<sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
<trade_type><![CDATA[JSAPI]]></trade_type>
</xml>
错误码
名称 | 描述 | 原因 | 解决方案 |
---|---|---|---|
NOAUTH | 商户无此接口权限 | 商户未开通此接口权限 | 请商户前往申请此接口权限 |
NOTENOUGH | 余额不足 | 用户帐号余额不足 | 用户帐号余额不足,请用户充值或更换支付卡后再支付 |
ORDERPAID | 商户订单已支付 | 商户订单已支付,无需重复操作 | 商户订单已支付,无需更多操作 |
ORDERCLOSED | 订单已关闭 | 当前订单已关闭,无法支付 | 当前订单已关闭,请重新下单 |
SYSTEMERROR | 系统错误 | 系统超时 | 系统异常,请用相同参数重新调用 |
APPID_NOT_EXIST | APPID不存在 | 参数中缺少APPID | 请检查APPID是否正确 |
MCHID_NOT_EXIST | MCHID不存在 | 参数中缺少MCHID | 请检查MCHID是否正确 |
APPID_MCHID_NOT_MATCH | appid和mch_id不匹配 | appid和mch_id不匹配 | 请确认appid和mch_id是否匹配 |
LACK_PARAMS | 缺少参数 | 缺少必要的请求参数 | 请检查参数是否齐全 |
OUT_TRADE_NO_USED | 商户订单号重复 | 同一笔交易不能多次提交 | 请核实商户订单号是否重复提交 |
SIGNERROR | 签名错误 | 参数签名结果不正确 | 请检查签名参数和方法是否都符合签名算法要求 |
XML_FORMAT_ERROR | XML格式错误 | XML格式错误 | 请检查XML参数格式是否正确 |
REQUIRE_POST_METHOD | 请使用post方法 | 未使用post传递参数 | 请检查请求参数是否通过post方法提交 |
POST_DATA_EMPTY | post数据为空 | post数据不能为空 | 请检查post数据是否为空 |
NOT_UTF8 | 编码格式错误 | 未使用指定编码格式 | 请使用UTF-8编码格式 |
一.后台回调类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Xml.Linq;
using ZhClass;
using Newtonsoft.Json;
namespace CS
{
/// <summary>
/// WXPay 的摘要说明
/// </summary>
public class WXPay
{
public WXPay() { }
public string XML()
{
return string.Format(@"
<xml>
<appid>{0}</appid>
<mch_id>{1}</mch_id>
<nonce_str>{2}</nonce_str>
<body>{3}</body>
<detail>{4}</detail>
<out_trade_no>{5}</out_trade_no>
<spbill_create_ip>{6}</spbill_create_ip>
<total_fee>{7}</total_fee>
<notify_url>{8}</notify_url>
<trade_type>{9}</trade_type>
<attach>{10}</attach>
<sign>{11}</sign>
</xml>",
this.appid, this.mch_id, this.nonce_str, this.body, this.detail, this.out_trade_no, this.spbill_create_ip, this.total_fee, this.notify_url, this.trade_type, this.attach, this.Sign());
}
/// <summary>
/// 公众账号ID(买家付款号)
/// </summary>
public string appid { get { return "wx7d9083d04*****"; } }
/// <summary>
/// 商户收款号
/// </summary>
public string mch_id { get { return "10058836"; } }
/// <summary>
/// 微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
/// </summary>
public string key { get { return "hkfdfdjidosdsf8yfao9p****f"; } }
/// <summary>
/// 随机字符串
/// </summary>
public string nonce_str
{
get { return ZhClass.ZH.Randow(20); }
}
/// <summary>
/// 交易类型
/// </summary>
public string trade_type
{
get { return "NATIVE"; }
}
/// <summary>
/// 订单描述
/// </summary>
public string body { get; set; }
/// <summary>
/// 商品详情,订单名称
/// </summary>
public string detail { get; set; }
/// <summary>
/// 附加数据(商户携带订单的自定义数据)
/// </summary>
public string attach { get; set; }
/// <summary>
/// 商户订单号
/// </summary>
public string out_trade_no { get; set; }
/// <summary>
/// 终端IP
/// </summary>
public string spbill_create_ip
{
get { return ZhClass.ZH.RealIP; }
}
/// <summary>
/// 总金额
/// </summary>
public int total_fee { get; set; }
/// <summary>
/// 通知地址,接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。
/// </summary>
public string notify_url
{
get { return "http://*****y.com/WXPay_Notify.ashx"; }
}
//请求微信支付方法
public string Pay()
{
return this.XML().Post("https://api.mch.weixin.qq.com/pay/unifiedorder");
}
/// <summary>
/// 签名方法
/// </summary>
public string Sign()
{
Dictionary<string, string> m = new Dictionary<string, string>();
try
{
Type type = typeof(WXPay);
object obj = Activator.CreateInstance(type);
type.GetProperties(BindingFlags.Public | BindingFlags.Instance).ForEach(t => m.Add(t.Name, t.GetValue(this, null).toString()));
#region 测试专用
ZH.SaveErr(string.Format("签名obj:{0}", JsonConvert.SerializeObject(obj)));
#endregion
m.Remove("key"); //这个已经内置了
m.Remove("sign");
return WXSign(m);
}
catch (Exception ex)
{
ZH.SaveErr(ex.ToString());
return "";
}
}
public string WXSign(Dictionary<string, string> m)
{
string stra = string.Join("&",
m.Where(t => !t.Value.IsNullOrEmpty()).OrderBy(t => t.Key).Select(t => string.Format("{0}={1}", t.Key, t.Value))
);
#region 测试专用
ZH.SaveErr(string.Format("签名stra:{0}", stra.toString()));
#endregion
string strb = string.Format("{0}&key={1}", stra, this.key);
return strb.Md5().ToUpper();
}
}
/// <summary>
/// 代替一般处理程序的类
/// </summary>
public class WXPay_Notify : IHttpHandler
{
//<xml>
//<appid><![CDATA[wx5d8187c****]]></appid> --公众账号ID(买家付款号)
//<attach><![CDATA[139294,2]]></attach> --附加数据
//<bank_type><![CDATA[COMM_DEBIT]]></bank_type> --银行类型
//<cash_fee><![CDATA[200]]></cash_fee> --现金金额
//<fee_type><![CDATA[CNY]]></fee_type> --标价币种
//<is_subscribe><![CDATA[Y]]></is_subscribe> --是否关注公众账号
//<mch_id><![CDATA[150****421]]></mch_id> --微信支付分配的商户号(商户收款号)
//<nonce_str><![CDATA[mU7SDeHzwy6iT7FSk5RZ]]></nonce_str> --随机字符串
//<openid><![CDATA[oSD1J02Cdt_daqcj****7Nhg]]></openid> --用户在商户系统下的唯一标识
//<out_trade_no><![CDATA[2018072*****5mU7SDeHzwy]]></out_trade_no> --商户订单流水号
//<result_code><![CDATA[SUCCESS]]></result_code> --业务结果:SUCCESS/FAIL
//<return_code><![CDATA[SUCCESS]]></return_code> --此字段是通信标识(SUCCESS/FAIL),非交易标识,交易是否成功需要查看trade_state来判断
//<sign><![CDATA[33613BB305C792****63E02CD27F1]]></sign> --签名,详见签名生成算法
//<time_end><![CDATA[20180720115253]]></time_end> --支付完成时间
//<total_fee>200</total_fee> --订单总金额
//<trade_type><![CDATA[NATIVE]]></trade_type> --交易类型
//<transaction_id><![CDATA[42000001162018****04937929]]></transaction_id> --微信支付订单号
//<trade_state_desc><![CDATA[支付失败,请重新下单支付]]></trade_state_desc> --交易状态描述
//</xml>
//微信承认的返回的result :
//成功:
//<xml>
//<return_code><![CDATA[SUCCESS]]></return_code>
//<return_msg><![CDATA[OK]]></return_msg>
//</xml>
//失败:
// <xml>
//<return_code><![CDATA[FAIL]]></return_code>
//<return_msg><![CDATA[状态失败]]></return_msg>
//</xml>
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.AddHeader("Cache-Control", "no-cache");
ExcuteResult result = new ExcuteResult();
//商户订单号
string out_trade_no = "";
string uname = "";
try
{
string notifyXml = context.Request.getPostData();
//记录回调的信息
ZH.SaveErr("微信支付异步回调通知信息:" + notifyXml);
XElement xe = XElement.Parse(notifyXml);
if (xe.Element("result_code").Value == "SUCCESS" && xe.Element("return_code").Value == "SUCCESS")
{
//获取回调的信息,将信息存储到数据库
//注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。
//特别提醒:商户系统对于支付结果通知的内容一定要做签名验证,防止数据泄漏导致出现“假通知”,造成资金损失。
//商户订单号
out_trade_no = xe.Element("out_trade_no") == null ? "" : xe.Element("out_trade_no").Value;
//微信订单号
string transaction_id = xe.Element("transaction_id") == null ? "" : xe.Element("transaction_id").Value;
//订单收款账号(卖家号)
string mch_id = xe.Element("mch_id") == null ? "" : xe.Element("mch_id").Value;
//订单付款账号(买家号)
string appid = xe.Element("appid") == null ? "" : xe.Element("appid").Value;
//订单总金额(传给微信和返回的金额都是 乘以100后的值)
decimal total_fee = xe.Element("total_fee") == null ? Convert.ToDecimal("0.00") :
Convert.ToDecimal(Math.Round((Convert.ToDouble(xe.Element("total_fee").Value)) / 100, 2));
#region 原先
//订单附加
string attach = xe.Element("attach") == null ? "" : xe.Element("attach").Value;
//订单交易支付时间
DateTime time_end = xe.Element("time_end") == null ? Convert.ToDateTime("1990-01-01") : DateTime.ParseExact(xe.Element("time_end").Value, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
//交易类型(0:支付宝 1:微信)
int order_pay_type = 1;
//订单详情
string order_detail = "";
//订单id
string order_id = "";
//订单名称
string order_name = "";
if (attach.Length > 0)
{
AlipayBody weiXinAttach = JsonConvert.DeserializeObject<AlipayBody>(attach);
uname = weiXinAttach.uname;
//order_detail = weiXinAttach.order_detail;
//order_id = weiXinAttach.order_id.toString();
//order_name = weiXinAttach.order_name.toString();
}
#endregion
//mch_id(收款微信账号对应的微信唯一用户号)一致
if (mch_id != new WXPay().mch_id)
{
result.Result = false;
result.Msg = "mch_id(收款微信账号对应的微信唯一用户号)与请求时不一致";
ZH.SaveErr(new ErrorLog()
{
ErrorId = out_trade_no,
ErrorUser = uname,
ErrorTime = DateTime.Now,
ErrorClass = "WXPay.cs",
ErrorMethod = "ProcessRequest",
ErrorMsg = result.toJson()
}.toJson());
//记录异常状态
UpdateErrorStateByReturnSuccessAlipay(uname, out_trade_no, transaction_id, order_name, mch_id, appid, order_pay_type, total_fee, order_detail, time_end);
context.Response.Write(@"
<xml>
< return_code >< ![CDATA[FAIL]] ></ return_code >
< return_msg > < ![CDATA[" + result.Msg + "]] ></ return_msg >" +
"</ xml > ");
context.ApplicationInstance.CompleteRequest();
}
//访问数据库,更新库存
var obj = DB.ExeSqlSaving("proc_order_validate_update_pay", "",
uname, out_trade_no, transaction_id, mch_id, appid, order_pay_type, total_fee, order_detail, time_end);
if (obj.Count != 4)
{
result.Result = false;
result.Msg = "存储过程的返回参数数量不对";
ZH.SaveErr(new ErrorLog()
{
ErrorId = out_trade_no,
ErrorUser = uname,
ErrorTime = DateTime.Now,
ErrorClass = "WXPay.cs",
ErrorMethod = "ProcessRequest",
ErrorMsg = result.toJson()
}.toJson());
context.Response.Write(@"
<xml>
< return_code >< ![CDATA[FAIL]] ></ return_code >
< return_msg > < ![CDATA[" + result.Msg + "]] ></ return_msg >" +
"</ xml > ");
context.ApplicationInstance.CompleteRequest();
}
result.Result = obj[1].toString(0) == 0 ? false : true;
result.Msg = obj[2].toString();
//注意:这里需要特别注意 代理商分成的返回,如果代理商分成有错误记录即可,不需要回滚所有订单信息
string order_propor_money_msg = obj[3].ToString();
if (order_propor_money_msg.Trim().Length > 0)
{
result.Msg = order_propor_money_msg;
}
ZH.SaveErr(new ErrorLog()
{
ErrorId = out_trade_no,
ErrorUser = uname,
ErrorTime = DateTime.Now,
ErrorClass = "WXPay.cs",
ErrorMethod = "ProcessRequest",
ErrorMsg = result.toJson()
}.toJson());
if (!result.Result)
{
context.Response.Write(@"
<xml>
< return_code >< ![CDATA[FAIL]] ></ return_code >
< return_msg > < ![CDATA[" + result.Msg + "]] ></ return_msg >" +
"</ xml > ");
context.ApplicationInstance.CompleteRequest();
}
//成功
context.Response.Write(@"
<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
</xml>");
context.ApplicationInstance.CompleteRequest();
}
else
{
ZhClass.ZH.SaveErr(new ErrorLog()
{
ErrorId = out_trade_no,
ErrorUser = uname,
ErrorTime = DateTime.Now,
ErrorClass = "WXPay.cs",
ErrorMethod = "ProcessRequest",
ErrorMsg = "微信支付异步回调通知状态失败!"
}.toJson());
context.Response.Write(@"
<xml>
<return_code><![CDATA[FAIL]]></return_code>
<return_msg><![CDATA[微信支付异步回调通知状态失败]]></return_msg>
</xml>");
context.ApplicationInstance.CompleteRequest();
}
}
catch (Exception ex)
{
ZhClass.ZH.SaveErr(new ErrorLog()
{
ErrorId = out_trade_no,
ErrorUser = uname,
ErrorTime = DateTime.Now,
ErrorClass = "WXPay.cs",
ErrorMethod = "ProcessRequest",
ErrorMsg = ex.toString()
}.toJson());
context.Response.Write(@"
<xml>
<return_code><![CDATA[FAIL]]></return_code>
<return_msg><![CDATA[ex异常]]></return_msg>
</xml>");
context.ApplicationInstance.CompleteRequest();
}
}
public bool IsReusable { get { return false; } }
/// <summary>
/// 微信返回支付成功,记录订单异常
/// </summary>
/// <param name="uname"></param>
/// <param name="order_flow_num"></param>
/// <param name="order_pay_num"></param>
/// <param name="order_subject"></param>
/// <param name="order_seller_id"></param>
/// <param name="order_buyer_id"></param>
/// <param name="order_pay_type"></param>
/// <param name="order_total_amount"></param>
/// <param name="order_memo"></param>
/// <param name="order_pay_time"></param>
public void UpdateErrorStateByReturnSuccessAlipay(string uname, string order_flow_num, string order_pay_num, string order_subject,
string order_seller_id, string order_buyer_id, int order_pay_type, decimal order_total_amount, string order_memo, DateTime order_pay_time)
{
ExcuteResult result = new ExcuteResult();
var obj = DB.ExeSqlSaving("proc_update_order_state_by_error", "", uname, order_flow_num, order_pay_num, order_subject, order_seller_id, order_buyer_id,
order_pay_type, order_total_amount, order_memo, order_pay_time);
}
}
}