.NET Core之微信支付之公衆號、H5支付篇

前言

本篇主要記錄微信支付中公衆號及H5支付全過程。javascript

準備篇

公衆號或者服務號(並開通微信支付功能)、商戶平臺中開通JSAPI支付、H5支付。php

配置篇

公衆號或者服務號中 -------開發-------開發者工具---------web開發者工具-------綁定爲開發者html

公衆號或者服務號中 -------公衆號設置--------功能設置   :填寫業務域名、JS安全域名、網頁受權域名 示例:pay.one.com前端

商戶平臺中--------產品中心-------開發配置------JSAPI支付受權目錄填寫:http://pay.one.com/    http://pay.one.com/WeChatPay/PubPay/-----H5支付填寫:pay.one.comjava

 

 

 

若對配置還有疑問,可參考官方文檔:jquery

https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842android

https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6ios

開發篇

JSAPI支付

本Demo是基於Payment 的SDK開發。具體詳情可參考:https://github.com/Essensoft/Paymentgit

首先 使用Nuget安裝payment:github

Install-Package  :Essensoft.AspNetCore.Payment.WeChatPay -Version 2.3.2

建一個Model: WeChatPayPubPayViewModel

 

public class WeChatPayPubPayViewModel
    {
        [Required]
        [Display(Name = "out_trade_no")]
        public string OutTradeNo { get; set; }

        [Required]
        [Display(Name = "body")]
        public string Body { get; set; }

        [Required]
        [Display(Name = "total_fee")]
        public int TotalFee { get; set; }

        [Required]
        [Display(Name = "spbill_create_ip")]
        public string SpbillCreateIp { get; set; }

        [Required]
        [Display(Name = "notify_url")]
        public string NotifyUrl { get; set; }

        [Required]
        [Display(Name = "trade_type")]
        public string TradeType { get; set; }

        [Required]
        [Display(Name = "openid")]
        public string OpenId { get; set; }
    }

WeChatPayController:

//微信支付請求客戶端(用於處理請求與響應)
private readonly IWeChatPayClient _client;
private readonly ILogger<WeChatPayController> _logger;

 private IHttpContextAccessor _accessor;

public WeChatPayController(IWeChatPayClient client, IHttpContextAccessor accessor, ILogger<WeChatPayController> logger)
        {
            _client = client;
            _accessor = accessor;
            _logger = logger;
        }
        /// <summary>
        /// 公衆號支付
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public  IActionResult PubPay()
        {
            WeChatPayPubPayViewModel payModel=new WeChatPayPubPayViewModel()
            {
                Body = "微信公衆號支付測試",
                OutTradeNo = DateTime.Now.ToString("yyyyMMddHHmmssfff"),
                TotalFee = 1,//分 單位
                SpbillCreateIp = "127.0.0.1",
                NotifyUrl = "http://pay.one.com/notify/wechatpay/unifiedorder",
                TradeType = "JSAPI",
                OpenId = "" //此處需進行受權 獲取OpenId
            };
            return View(payModel);
        }

        /// <summary>
        /// 公衆號支付
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> PubPay(WeChatPayPubPayViewModel viewModel)
        {
           if(string.IsNullOrEmpty(viewModel.OpenId))
           {
               ViewData["response"] = "請返回上級從新進入此頁面以獲取最新數據";
               return View();
           }

            var request = new WeChatPayUnifiedOrderRequest
            {
                Body = viewModel.Body,
                OutTradeNo = viewModel.OutTradeNo,
                TotalFee = viewModel.TotalFee,
                SpbillCreateIp = viewModel.SpbillCreateIp,
                NotifyUrl = viewModel.NotifyUrl,
                TradeType = viewModel.TradeType,
                OpenId = viewModel.OpenId //此處需進行受權 獲取OpenId
            };
            var response = await _client.ExecuteAsync(request);if (response.ReturnCode == "SUCCESS" && response.ResultCode == "SUCCESS")
            {
                var req = new WeChatPayH5CallPaymentRequest
                {
                    Package = "prepay_id=" + response.PrepayId
                };
                var parameter = await _client.ExecuteAsync(req);
                // 將參數(parameter)給 公衆號前端 讓他在微信內H5調起支付(https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6)
                ViewData["parameter"] = JsonConvert.SerializeObject(parameter);
                ViewData["response"] = response.Body;
                return View();
            }
            ViewData["response"] = response.Body;
            return View();
        }

注意:公衆號或者微信內支付,須要受權獲取到用戶的OpenId。因此,此處咱們還須要進行微信受權,而受權方式有兩種,一種是靜默受權、一種是須要用戶贊成,區別是 靜默受權只能拿到Openid,而經用戶贊成後可拿到 微信頭像、暱稱、性別等其餘信息。

具體可參閱文檔:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842

頁面:

@using Newtonsoft.Json
@model WeChatPayPubPayViewModel
@{
    ViewData["Title"] = "公衆號支付-統一下單";
}
<nav aria-label="breadcrumb">
    <ol class="breadcrumb">
        <li class="breadcrumb-item"><a asp-controller="WeChatPay" asp-action="Index">微信支付</a></li>
        <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
    </ol>
</nav>
<br />
<div class="card">
    <div class="card-body">
        <form asp-controller="WeChatPay" asp-action="PubPay">
            <div asp-validation-summary="All" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="OutTradeNo"></label>
                <input type="text" class="form-control" asp-for="OutTradeNo" value="@Model?.OutTradeNo" />
            </div>
            <div class="form-group">
                <label asp-for="Body"></label>
                <input type="text" class="form-control" asp-for="Body" value="@Model?.Body" />
            </div>
            <div class="form-group">
                <label asp-for="TotalFee"></label>
                <input type="text" class="form-control" asp-for="TotalFee" value="@Model?.TotalFee" />
            </div>
            <div class="form-group">
                <label asp-for="SpbillCreateIp"></label>
                <input type="text" class="form-control" asp-for="SpbillCreateIp" value="@Model?.SpbillCreateIp" />
            </div>
            <div class="form-group">
                <label asp-for="NotifyUrl"></label>
                <input type="text" class="form-control" asp-for="NotifyUrl" value="@Model?.NotifyUrl" />
            </div>
            <div class="form-group">
                <label asp-for="TradeType"></label>
                <input type="text" class="form-control" asp-for="TradeType" value="@Model?.TradeType" />
            </div>
            <div class="form-group">
                <label asp-for="OpenId"></label>
                <input type="text" class="form-control" asp-for="OpenId" value="@Model?.OpenId" />
            </div>
            <button type="submit" class="btn btn-primary">提交請求</button>
            <button type="button" class="btn btn-success" id="PayNow">當即支付</button>
        </form>
        <hr />
        <form class="form-horizontal">
            <div class="form-group">
                <label>Response:</label>
                <textarea class="form-control" rows="10">@ViewData["response"]</textarea>
            </div>
            <div class="form-group">
                <label>Parameter:</label>
                <textarea class="form-control" rows="3">@ViewData["parameter"]</textarea>
            </div>
        </form>
    </div>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script type="text/javascript">
    $(function () {
        $("#PayNow").on('click', function () {
            const local = "http://pay.one.com/WeChatPay/PayBack/";  
              window.location.href ='https://open.weixin.qq.com/connect/oauth2/authorize?appid=@ViewBaig.AppId&redirect_uri=' + encodeURIComponent(local)+'&response_type=code&scope=snsapi_base&state=a#wechat_redirect';
        });
   
    });

</script>

此時:PayBack Action以下:

 [HttpGet]
        public async  Task<IActionResult> PayBack()
        {
            var code = Request.Query["code"];
            var state = Request.Query["state"];
            OAuthToken tokenModel = new OAuthToken();
            //經過code換取token
            if (!string.IsNullOrEmpty(code))
            {
                _logger.LogWarning("受權成功");
                ViewBag.Code = code;
                tokenModel = OauthApi.GetAuthToken(code, wechatAppId);
            }

            var request = new WeChatPayUnifiedOrderRequest
            {
                Body = "微信公衆號支付測試",
                OutTradeNo = DateTime.Now.ToString("yyyyMMddHHmmssfff"),
                TotalFee = 1,//分 單位
                SpbillCreateIp = "127.0.0.1",
                NotifyUrl = "http://pay.one.com/notify/wechatpay/unifiedorder",
                TradeType = "JSAPI",
                OpenId = tokenModel.Openid //此處需進行受權 獲取OpenId
            };
            var response = await _client.ExecuteAsync(request);
            _logger.LogWarning($"統一下單接口返回:{response.ReturnCode}");

            if (response.ReturnCode == "SUCCESS" && response.ResultCode == "SUCCESS")
            {
                var req = new WeChatPayH5CallPaymentRequest
                {
                    Package = "prepay_id=" + response.PrepayId
                };
                var parameter = await _client.ExecuteAsync(req);
                // 將參數(parameter)給 公衆號前端 讓他在微信內H5調起支付(https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6)
                ViewData["parameter"] = JsonConvert.SerializeObject(parameter);
                _logger.LogWarning($"統一下單成功,即將調起微信支付:{ViewData["parameter"].ToString()}");
                ViewData["response"] = response.Body;

             if (ViewData["parameter"] != null)
                  {
                     ViewBag.Test = JsonConvert.DeserializeObject(ViewData["parameter"]?.ToString());
                  }

return View();
            }
            ViewData["response"] = response.Body;

            
            return View();
        }

其中:OAuthToken是網頁受權 返回的實體:

/// 獲取網頁受權token時,返回的實體
    /// </summary>
    public class OAuthToken : BaseRes
    {
        /// <summary>
        /// 網頁受權接口調用憑證。注意:此access_token與基礎支持的access_token不一樣
        /// </summary>
        [JsonProperty("access_token")]
        public string AccessToken { get; set; }
        private int _expiresIn;
        /// <summary>
        /// access_token接口調用憑證超時時間,單位(秒)
        /// </summary>
        [JsonProperty("expires_in")]
        public int ExpiresIn
        {
            get { return _expiresIn; }
            set
            {
                ExpiresTime = DateTime.Now.AddSeconds(value);
                _expiresIn = value;
            }
        }
        /// <summary>
        /// 用於刷新access_token
        /// </summary>
        [JsonProperty("refresh_token")]
        public string RefreshToken { get; set; }
        /// <summary>
        /// 用戶惟一標識。請注意,在未關注公衆號時,用戶訪問公衆號的網頁,也會產生一個用戶和公衆號惟一的openid
        /// </summary>
        [JsonProperty("openid")]
        public string Openid { get; set; }
        /// <summary>
        /// 用戶受權的做用域,使用逗號(,)分隔
        /// </summary>
        [JsonProperty("scope")]
        public string Scope { get; set; }
        [JsonProperty("expires_time")]
        public DateTime ExpiresTime { get; set; }
        /// <summary>
        /// 只有在用戶將公衆號綁定到微信開放平臺帳號後,纔會出現該字段
        /// </summary>
        [JsonProperty("unionid")]
        public string Unionid { get; set; }
    }
View Code

而後PayBack返回的視圖至關於一個支付過渡頁中 帶有微信的js標識,能夠主動調起微信支付,大概視圖以下:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <title>正在支付</title>
</head>
<body>
    <div class="row paytop30" style="text-align: center;margin-top: 30px">
        <div class="col-xs-12 text-center ">
            <img src="~/Images/registerNewSite/pay.gif" class="payLoding" style="width: 130px;height:100px" />
            <p class="registEidtText" id="backText"></p>
        </div>
    </div>

    <script src="~/lib/layer/layer.js"></script>
    <script type="text/javascript">
    $(function() {
        @{
            var appId = ViewBag.Test?.appId;
            var timeStamp = ViewBag.Test?.timeStamp;
            var nonceStr = ViewBag.Test?.nonceStr;
            var package = ViewBag.Test?.package;
            var signType = ViewBag.Test?.signType;
            var paySign = ViewBag.Test?.paySign;
        }
        onBridgeReady();
    });

    function onBridgeReady() {
        WeixinJSBridge.invoke(
            'getBrandWCPayRequest',
            {
                "appId": "@appId",
                "timeStamp": "@timeStamp",
                "nonceStr": "@nonceStr",
                "package": "@package",
                "signType": "@signType",
                "paySign": "@paySign"
            },
            function(res) {

                if (res.err_msg == "get_brand_wcpay_request:ok") {
                    // 使用以上方式判斷前端返回,微信團隊鄭重提示:
                    //res.err_msg將在用戶支付成功後返回ok,但並不保證它絕對可靠。
                    $("#backText").html('即將跳轉訂單詳情頁');
                    setTimeout(function() {
                        window.location.href = "支付詳情頁";
                        },
                        2000);
                } else {
                    $("#backText").html('即將跳轉訂單詳情頁');
                    setTimeout(function() {
                        window.location.href = "支付詳情頁"; 
            },
2000);
          }
    });
  }
if (typeof WeixinJSBridge == "undefined") { 
  if (document.addEventListener) {
    document.addEventListener(
'WeixinJSBridgeReady', onBridgeReady, false);
   }
else if (document.attachEvent) {
    document.attachEvent(
'WeixinJSBridgeReady', onBridgeReady);
     document.attachEvent(
'onWeixinJSBridgeReady', onBridgeReady);
  }
}
else {
  onBridgeReady();
}
</script>
</body>
</html>

 

最後 貼一下支付成功後的回調函數:

[Route("notify/wechatpay")]
    public class WeChatPayNotifyController : Controller
    {
        private readonly IWeChatPayNotifyClient _client;
        private readonly ILogger<WeChatPayNotifyController> _logger;
        public WeChatPayNotifyController(IWeChatPayNotifyClient client,ILogger<WeChatPayNotifyController> logger)
        {
            _client = client;
            _logger = logger;
        }

        /// <summary>
        /// 統一下單支付結果通知
        /// </summary>
        /// <returns></returns>
        [Route("unifiedorder")]
        [HttpPost]
        public async Task<IActionResult> Unifiedorder()
        {
            try
            {
                _logger.LogWarning($"進入回調");
                var payconfig = OpenApi.GetPayConfig();
                var notify = await _client.ExecuteAsync<WeChatPayUnifiedOrderNotify>(Request);
                _logger.LogWarning($"返回狀態碼:{notify.ReturnCode}");

                if (notify.ReturnCode == "SUCCESS")
                {
                    _logger.LogWarning($"業務結果碼:{notify.ResultCode}");

                    if (notify.ResultCode == "SUCCESS")
                    {
                        _logger.LogWarning($"支付方式:{notify.TradeType}");
                        _logger.LogWarning($"商戶訂單號:{notify.OutTradeNo}");
                        _logger.LogWarning($"微信支付訂單號:{notify.TransactionId}");
                        _logger.LogWarning($"支付金額:{notify.TotalFee}");
//本身的業務
return WeChatPayNotifyResult.Success; } } return NoContent(); } catch(Exception ex) { _logger.LogWarning($"回調失敗:{ex.Message}"); return NoContent(); } } }

而後測試一下支付,查看服務器Log以下:

 

 

H5支付

 H5支付是指再除開微信瀏覽器之外的移動端瀏覽器上進行微信回覆操做。

和上面步驟大致一致,有幾個地方須要注意

1:客戶端IP問題:H5支付的時候,微信支付系統會根據客戶端調起的當前Ip 做爲支付Ip,若發現 發起支付請求時,ip有問題,則會支付失敗,或者提示系統繁忙。這裏貼一下我獲取IP的代碼:

Utils.GetUserIp(_accessor.HttpContext);//頁面上調用         /// <summary>
        /// 穿過代理服務器獲取真實IP
        /// </summary>
        /// <returns></returns>
        public static string GetUserIp(this HttpContext context)
        {
            var ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ip))
            {
                ip = context.Connection.RemoteIpAddress.ToString();
            }
            return ip;
            
        }

2:TradeType類型應該是:MWEB

3:若調起微信支付成功後,默認回調到支付首頁,若須要設置回調頁面,則能夠再URl中拼接:

        /// <summary>
        /// H5支付
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> H5Pay(WeChatPayH5PayViewModel viewModel)
        {
            var request = new WeChatPayUnifiedOrderRequest
            {
                Body = viewModel.Body,
                OutTradeNo = viewModel.OutTradeNo,
                TotalFee = viewModel.TotalFee,
                SpbillCreateIp = viewModel.SpbillCreateIp,
                NotifyUrl = viewModel.NotifyUrl,
                TradeType = viewModel.TradeType
            };
            var response = await _client.ExecuteAsync(request);

            // mweb_url爲拉起微信支付收銀臺的中間頁面,可經過訪問該url來拉起微信客戶端,完成支付,mweb_url的有效期爲5分鐘。
            if (response.MwebUrl == null)
            {
                ViewData["response"] = response.ReturnMsg;
                return View();
            }
            return Redirect(response.MwebUrl);
        }

更多詳細可參考文檔:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_4

 

4:支付結果通知:

完整Demo

 $("#PayNow").on("click",
        function () {
            var result = isWeiXin();
            var orderId = $(this).attr("data-orderId");
            var pay = $(this).attr("data-pay");
            var userId = $(this).attr("data-userId");
            var account = $(this).attr("data-account");
            var matchId = $(this).attr("data-matchId");
            if (result === 0) {
//                layer.msg(pay);
                const local = "支付網址/WeChatPay/PayBack?pay=" + pay + "&userId=" + parseInt(userId) + "&account=" + account + "&matchId=" + parseInt(matchId) +"&orderId="+orderId;
                window.location.href =
                    'https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxdd269ffaec1a1725&redirect_uri=' +
                    encodeURIComponent(local) +
                    '&response_type=code&scope=snsapi_base&state=a#wechat_redirect';
            } else if (result === 1) {
                window.location.href = "/WeChatPay/H5Pay?pay=" + pay + "&userId=" + parseInt(userId) + "&account=" + account + "&matchId=" + parseInt(matchId) + "&orderId=" + orderId;
            } else {
                layer.msg('請使用移動設備完成支付');
            }
        });

 

//判斷是不是微信瀏覽器的函數
    function isWeiXin() {
        //window.navigator.userAgent屬性包含了瀏覽器類型、版本、操做系統類型、瀏覽器引擎類型等信息,這個屬性能夠用來判斷瀏覽器類型
        if (browser.versions.mobile) {//判斷是不是移動設備打開。browser代碼在下面
            var ua = navigator.userAgent.toLowerCase();//獲取判斷用的對象
            if (ua.match(/MicroMessenger/i) == "micromessenger") {
                return 0;
            } else {
                return 1;
            }
        } else {
            //不然就是PC瀏覽器打開
            return 2;
        }
    }

    var browser = {
        versions: function () {
            var u = navigator.userAgent, app = navigator.appVersion;
            return {         //移動終端瀏覽器版本信息
                trident: u.indexOf('Trident') > -1, //IE內核
                presto: u.indexOf('Presto') > -1, //opera內核
                webKit: u.indexOf('AppleWebKit') > -1, //蘋果、谷歌內核
                gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐內核
                mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否爲移動終端
                ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios終端
                android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android終端或uc瀏覽器
                iPhone: u.indexOf('iPhone') > -1, //是否爲iPhone或者QQHD瀏覽器
                iPad: u.indexOf('iPad') > -1, //是否iPad
                webApp: u.indexOf('Safari') == -1 //是否web應該程序,沒有頭部與底部
            };
        }(),
        language: (navigator.browserLanguage || navigator.language).toLowerCase()
    }
 [HttpGet]
        public async Task<IActionResult> H5Pay()
        {
            var pay = Request.Query["pay"];
            var userId = Request.Query["userId"];
            var account = Request.Query["account"];
            var matchId = Request.Query["matchId"];
            var orderId = Request.Query["orderId"];
            var model = new WeChatPayUnifiedOrderRequest()
            {
                Body = "賽事雲平臺在線報名費",
                OutTradeNo = DateTime.Now.ToString("yyyyMMddHHmmssfff"),
                TotalFee = int.Parse(pay),//分 須要*100 獲得元
                SpbillCreateIp = Utils.GetUserIp(_httpContextAccessor.HttpContext),
                NotifyUrl = "支付網址/notify/wechatpay/unifiedorder/"+long.Parse(matchId),//帶一個數據Id,能夠根據本身業務須要替換
                TradeType = "MWEB"
            };
            var response = await _client.ExecuteAsync(model);

            // mweb_url爲拉起微信支付收銀臺的中間頁面,可經過訪問該url來拉起微信客戶端,完成支付,mweb_url的有效期爲5分鐘。
            if (response.MwebUrl == null)
            {
                ViewData["response"] = response.ReturnMsg;//異常
                _logger.LogError($"H5支付出現異常:{response.ReturnMsg}");
                return Redirect(response.MwebUrl); 
            }
           
            //將下單數據存入訂單支付表 根據本身業務須要自行替換
            OrderPayModel orderPay = new OrderPayModel()
            {
                OrderId = int.Parse(orderId),
                OrderNumber = model.OutTradeNo,
                UserId = int.Parse(userId),
                LoginAccount = account,
                IsPay = false,
                OrderMoney = decimal.Parse(pay),
                PayType = PayType.MWEB,
                CreteDateTime = DateTime.Now
            };
            if (!string.IsNullOrEmpty(matchId)  && !string.IsNullOrEmpty(orderId))
            {
                var addBack = await _crewManager.AddOrderPay(int.Parse(matchId), orderPay);
            }

            return Redirect(response.MwebUrl);
        }

 

回調:

/// <summary>
        /// 統一下單支付結果通知
        /// </summary>
        /// <returns></returns>
        [Route("unifiedorder/{matchId}")] //能夠跟一個參數
        [HttpPost]
        public async Task<IActionResult> Unifiedorder(int matchId)
        {
            try
            {
                var payconfig = OpenApi.GetPayConfig();
                var notify = await _client.ExecuteAsync<WeChatPayUnifiedOrderNotify>(Request);

                if (notify.ReturnCode == "SUCCESS")
                {
                    if (notify.ResultCode == "SUCCESS")
                    {
                        //根據訂單號修改訂單支付狀態及金額
                        OrderPayModel model = new OrderPayModel()
                        {
                            OrderNumber = notify.OutTradeNo,
                            PayMoeny = decimal.Parse(notify.TotalFee),
                            IsPay = true,
                            TransactionId = notify.TransactionId,
                            PaidDate = DateTime.Now
                        };
              //根據本身項目業務自行調整
if (matchId!=0) { var result = await _crewManager.BackOrderPay(matchId, model); } return WeChatPayNotifyResult.Success; } } return NoContent(); } catch (Exception ex) { _logger.LogInformation($"回調失敗:{ex.Message}"); return NoContent(); } }

 

注意:

一、一樣的通知可能會屢次發送給商戶系統。商戶系統必須可以正確處理重複的通知。

二、後臺通知交互時,若是微信收到商戶的應答不符合規範或超時,微信會斷定本次通知失敗,從新發送通知,直到成功爲止(在通知一直不成功的狀況下,微信總共會發起10次通知,通知頻率爲15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 總計 24h4m),但微信不保證通知最終必定能成功。

三、在訂單狀態不明或者沒有收到微信支付結果通知的狀況下,建議商戶主動調用微信支付【查詢訂單API】確認訂單狀態。

特別提醒:

一、商戶系統對於支付結果通知的內容必定要作簽名驗證,並校驗返回的訂單金額是否與商戶側的訂單金額一致,防止數據泄漏致使出現「假通知」,形成資金損失。

二、當收到通知進行處理時,首先檢查對應業務數據的狀態,判斷該通知是否已經處理過,若是沒有處理過再進行處理,若是處理過直接返回結果成功。在對業務數據進行狀態檢查和處理以前,要採用數據鎖進行併發控制,以免函數重入形成的數據混亂。 

 

最後能夠測試下H5支付,查看返回的Log:

 

 本文只是拋磚引玉,更多具體支付場景和代碼,還需各位看官結合本身項目量身定作。

  更多示例Demo可入羣獲取。

相關文章
相關標籤/搜索