C#微信支付(六)—— 通知回撥
阿新 • • 發佈:2018-12-09
這是重頭戲了,修改訂單狀態一般就是兩個地方,一個是前臺輪訓後發現微信訂單完成後修改狀態,另一個就是通知回撥那了。
通知回撥類,修改了下微信Demo程式碼,相容了支付和退款兩種情況,覺得放一起不好的,想分成兩個介面就拆開就好了
/// <summary>
/// 支付結果通知回撥處理類
/// 負責接收微信支付後臺傳送的支付結果並對訂單有效性進行驗證,將驗證結果反饋給微信支付後臺
/// </summary>
public class ResultNotify : Notify
{
public override WxPayData ProcessNotify (HttpContext context)
{
WxPayData notifyData = GetNotifyData(context);
//支付回撥
if (notifyData.IsSet("result_code"))
{
#region 驗證簽名
try
{
notifyData.CheckSign();//驗證簽名,不通過會拋異常
}
catch (Exception ex)
{
//若簽名錯誤,則立即返回結果給微信支付後臺
WxPayData res = new WxPayData();
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", ex.Message);
//Log.Error(this.GetType().ToString(), "Sign check error : " + res.ToXml());
context.Response.Write(res.ToXml());
return null;
}
#endregion
//檢查支付結果中transaction_id是否存在
if (!notifyData.IsSet("transaction_id"))
{
//若transaction_id不存在,則立即返回結果給微信支付後臺
WxPayData res = new WxPayData();
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", "支付結果中微信訂單號不存在");
//Log.Error(this.GetType().ToString(), "The Pay result is error : " + res.ToXml());
context.Response.Write(res.ToXml());
}
else
{
string transaction_id = notifyData.GetValue("transaction_id").ToString();
//查詢訂單,判斷訂單真實性
if (!QueryPayOrder(transaction_id))
{
//若訂單查詢失敗,則立即返回結果給微信支付後臺
WxPayData res = new WxPayData();
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", "訂單查詢失敗");
//Log.Error(this.GetType().ToString(), "Order query failure : " + res.ToXml());
context.Response.Write(res.ToXml());
}
//查詢訂單成功
else
{
WxPayData res = new WxPayData();
res.SetValue("return_code", "SUCCESS");
res.SetValue("return_msg", "OK");
//Log.Info(this.GetType().ToString(), "order query success : " + res.ToXml());
context.Response.Write(res.ToXml());
return notifyData;
}
}
}
//退款回撥
else if (notifyData.IsSet("req_info"))
{
if (!notifyData.IsSet("return_code") || notifyData.GetValue("return_code").ToString() != "SUCCESS" || !notifyData.IsSet("req_info"))
{
WxPayData res = new WxPayData();
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", "未返回正確微信支付退款解密資訊");
context.Response.Write(res.ToXml());
}
//資訊解密
string req_info = DecodeReqInfo(notifyData.GetValue("req_info").ToString());
if (req_info == null)
{
WxPayData res = new WxPayData();
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", "解密資訊出錯");
context.Response.Write(res.ToXml());
}
else
{
WxPayData res = new WxPayData();
res.SetValue("return_code", "SUCCESS");
res.SetValue("return_msg", "OK");
//Log.Info(this.GetType().ToString(), "order query success : " + res.ToXml());
context.Response.Write(res.ToXml());
//FormXML會校驗簽名
WxPayData riData = new WxPayData();
riData.FromXmlNoCheck(req_info);
notifyData.SetValue("req_info", riData);
return notifyData;
}
}
else
{
WxPayData res = new WxPayData();
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", "未知的通知回撥");
context.Response.Write(res.ToXml());
}
return null;
}
//查詢訂單
private bool QueryPayOrder(string transaction_id)
{
WxPayData req = new WxPayData();
req.SetValue("transaction_id", transaction_id);
WxPayData res = WxPayApi.OrderQuery(req);
if (res.GetValue("return_code").ToString() == "SUCCESS" &&
res.GetValue("result_code").ToString() == "SUCCESS")
{
return true;
}
else
{
return false;
}
}
#region 退款解密
/// <summary>
/// AES-256-ECB字元解密
/// </summary>
/// <param name="s">要解密字串</param>
/// <param name="key">金鑰</param>
/// <returns></returns>
public static string DecodeAES256ECB(string s, string key)
{
string r = null;
try
{
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] toEncryptArray = Convert.FromBase64String(s);
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.Mode = CipherMode.ECB;
rDel.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = rDel.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
r = UTF8Encoding.UTF8.GetString(resultArray);
}
catch { }
return r;
}
/// <summary>
/// 解密微信支付退款結果通知
/// </summary>
/// <param name="s">要解密字串</param>
/// <returns></returns>
public static string DecodeReqInfo(string s)
{
string r = null;
string key = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(Config.Key, "md5").ToLower();
r = DecodeAES256ECB(s, key);
return r;
}
#endregion
}
具體介面呼叫
public void ProcessRequest(HttpContext context)
{
ResultNotify resultNotify = new ResultNotify();
WxPayData notifyData = resultNotify.ProcessNotify(context);
if (notifyData != null)
{
//支付回撥
if (notifyData.IsSet("result_code"))
{
//TODO:核對訂單金額與微信訂單是否一致
//TODO:核對訂單金額與系統訂單是否一致
//TODO:核對訂單號,系統訂單號,商戶訂單號三者是否一致
//TODO:修改訂單狀態
//TODO:記錄日誌
}
//退款回撥
else if (notifyData.IsSet("req_info"))
{
//TODO:核對退款金額與系統退款是否一致
//TODO:核對訂單號,系統訂單號,商戶訂單號三者是否一致
//TODO:修改訂單狀態
//TODO:記錄日誌
}
}
}
一定要核對下訂單金額和訂單號,並且返回結果給微信,不然前者會有假冒資料,後者會讓微信幾分鐘內一直髮請求給你。。。。。
解密那有點坑,解密的流程有點繁瑣,遇到好幾次錯誤才通過了。其他的沒啥想到的,感覺出錯都是自己程式碼問題,微信那好像沒什麼坑,另外這個回撥並不是即時傳送的,有延遲的,微信那邊人多的時候,有一次30多秒才收到回撥。。。所以實際開發的時候,最好輪訓和回撥都要有。