欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

微信小程序netcore后台api支付结果通知接口的坑

程序员文章站 2024-02-12 08:27:40
...

终于搞定回调通知了,这里总结下几个暗坑

1.回调通知一定是post接口,且可以直接访问

2.需要解析回调的HttpContext内容才能知道结果

3.收到信息一定要进行验证判断是否来自于微信渠道

4.回调信息要去重,防止重复接收

5.无论成功与否,都要给微信回复个标准模板,否则微信会一直给你发

因为封装entity很麻烦,所以直接用盛派的SDK,引用如下:

微信小程序netcore后台api支付结果通知接口的坑

 

        /// <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"时才会有详细信息,成功后微信会把订单的详细结果发过来,如图:

微信小程序netcore后台api支付结果通知接口的坑

最后,正确返回微信结果很重要,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>";
        }