微信小程序netcore后台api支付结果通知接口的坑
程序员文章站
2024-02-12 08:27:40
...
终于搞定回调通知了,这里总结下几个暗坑
1.回调通知一定是post接口,且可以直接访问
2.需要解析回调的HttpContext内容才能知道结果
3.收到信息一定要进行验证判断是否来自于微信渠道
4.回调信息要去重,防止重复接收
5.无论成功与否,都要给微信回复个标准模板,否则微信会一直给你发
因为封装entity很麻烦,所以直接用盛派的SDK,引用如下:
/// <summary>
/// 支付回调地址(在统一下单接口中设置notify_url)
/// https://localhost:44373/api/WxPay/PayNotifyUrl
/// 注意:回调必须是post
/// </summary>
/// <returns></returns>
[HttpPost("PayNotifyUrl")]
public ActionResult PayNotifyUrl()
{
try
{
var resHandler = new ResponseHandler(HttpContext);
var return_code = resHandler.GetParameter("return_code");
var return_msg = resHandler.GetParameter("return_msg");
var openid = resHandler.GetParameter("openid");
resHandler.SetKey(TenPayV3Info.ApiKey);
//验证请求是否从微信发过来(安全)
if (!resHandler.IsTenpaySign())
{
// 验证不通过,支付失败
throw new Exception($"支付验证不通过:[{return_code}][{return_msg}][{openid}]");
}
var notify = new PaidNotify
{
ResultCode = return_code,
ReturnMsg = return_msg,
Openid = openid,
};
if (return_code.ToUpper() == "SUCCESS")
{
//直到这里,才能认为交易真正成功了,可以进行数据库操作,但是别忘了返回规定格式的消息!
notify.Appid = GetTxt(resHandler, "appid");
notify.MchId = GetTxt(resHandler, "mch_id");
notify.DeviceInfo = GetTxt(resHandler, "device_info");
notify.NonceStr = GetTxt(resHandler, "nonce_str");
notify.Sign = GetTxt(resHandler, "sign");
notify.SignType = GetTxt(resHandler, "sign_type");
notify.ResultCode = GetTxt(resHandler, "result_code");
notify.ErrCode = GetTxt(resHandler, "err_code");
notify.ErrCodeDes = GetTxt(resHandler, "err_code_des");
notify.Openid = GetTxt(resHandler, "openid");
notify.IsSubscribe = GetTxt(resHandler, "is_subscribe");
notify.TradeType = GetTxt(resHandler, "trade_type");
notify.BankType = GetTxt(resHandler, "bank_type");
notify.TotalFee = GetInt(resHandler, "total_fee");
notify.SettlementTotalFee = GetInt(resHandler, "settlement_total_fee");
notify.FeeType = GetTxt(resHandler, "fee_type");
notify.CashFee = GetInt(resHandler, "cash_fee");
notify.CashFeeType = GetTxt(resHandler, "cash_fee_type");
notify.CouponFee = GetInt(resHandler, "coupon_fee");
notify.CouponCount = GetInt(resHandler, "coupon_count");
notify.CouponTypeN = GetTxt(resHandler, "coupon_type_$n");
notify.CouponIdN = GetTxt(resHandler, "coupon_id_$n");
notify.CouponFeeN = GetInt(resHandler, "coupon_fee_$n");
notify.TransactionId = GetTxt(resHandler, "transaction_id");
notify.OutTradeNo = GetTxt(resHandler, "out_trade_no");
notify.Attach = GetTxt(resHandler, "attach");
notify.TimeEnd = GetTxt(resHandler, "time_end");
}
#region 发送支付成功的模板消息
try
{
var appId = TenPayV3Info.WebId;//与微信公众账号后台的AppId设置保持一致,区分大小写。
var templateData = new WeixinTemplate_PaySuccess(NotifyUrl, "购买商品", "状态:" + return_code);
SenparcTrace.SendCustomLog("支付成功模板消息参数", appId + " , " + openid);
//var result = AdvancedAPIs.TemplateApi.SendTemplateMessage(appId, openId, templateData);
}
catch (Exception ex)
{
SenparcTrace.SendCustomLog("支付成功模板消息", ex.ToString());
}
#endregion
// 添加支付结果记录
//PaymentService.AddPaidNotify(notify);
var xml = AppPay.PayNotifyXml(return_code, return_msg);
return Content(xml, "text/xml");
}
catch (Exception ex)
{
var err = new WeixinException(ex.Message, ex);
Log(err.Message);
var xml = AppPay.PayNotifyXml("FAIL", ex.Message);
return Content(xml, "text/xml");
}
}
static int? GetInt(ResponseHandler handler, string key)
{
var txt = handler.GetParameter(key);
return int.TryParse(txt, out var num) ? (int?)num : null;
}
static string GetTxt(ResponseHandler handler, string key)
{
return handler.GetParameter(key);
}
/// <summary>
/// 日志记录
/// </summary>
/// <param name="msg"></param>
static void Log(string msg)
{
var logDir = ServerUtility.ContentRootMapPath($"~/App_Data/PayNotifyUrl/{SystemTime.Now:yyyyMMdd}");
if (!Directory.Exists(logDir))
{
Directory.CreateDirectory(logDir);
}
var logPath = Path.Combine(logDir, $"{SystemTime.Now:yyyyMMdd}-{SystemTime.Now:HHmmss}-{Guid.NewGuid().ToString("n").Substring(0, 8)}.txt");
using (var fileStream = System.IO.File.OpenWrite(logPath))
{
fileStream.Write(Encoding.Default.GetBytes(msg), 0, Encoding.Default.GetByteCount(msg));
fileStream.Close();
}
}
只有收到return_code="success"时才会有详细信息,成功后微信会把订单的详细结果发过来,如图:
最后,正确返回微信结果很重要,xml格式如下:
/// <summary>
/// 收到财付通消息后返回的回调通知
/// </summary>
/// <param name="return_code"></param>
/// <param name="return_msg"></param>
/// <returns></returns>
public static string PayNotifyXml(string return_code = "SUCCESS", string return_msg = "OK")
{
return aaa@qq.com"<xml><return_code><![CDATA[{return_code}]]></return_code><return_msg><![CDATA[{return_msg}]]></return_msg></xml>";
}