.net Core數據的幕等性

来源:https://www.cnblogs.com/chenxi001/archive/2019/10/13/11668541.html
-Advertisement-
Play Games

一、背景 代碼實例:https://gitee.com/D_C_L/CurtainEtcAOP.git我們實際系統中有很多操作,是不管做多少次,都應該產生一樣的效果或返回一樣的結果。 例如: 1. 前端重覆提交選中的數據,應該後臺只產生對應這個數據的一個反應結果。 2. 我們發起一筆付款請求,應該只 ...


一、背景 

代碼實例:https://gitee.com/D_C_L/CurtainEtcAOP.git
我們實際系統中有很多操作,是不管做多少次,都應該產生一樣的效果或返回一樣的結果。 
例如:
 

1. 前端重覆提交選中的數據,應該後臺只產生對應這個數據的一個反應結果。 
2. 我們發起一筆付款請求,應該只扣用戶賬戶一次錢,當遇到網路重發或系統bug重發,也應該只扣一次錢; 
3. 發送消息,也應該只發一次,同樣的簡訊發給用戶,用戶會哭的; 
4. 創建業務訂單,一次業務請求只能創建一個,創建多個就會出大問題。 

等等很多重要的情況,這些邏輯都需要冪等的特性來支持。 

二、冪等性概念
 
冪等(idempotent、idempotence)是一個數學與電腦學概念,常見於抽象代數中。 

在編程中.一個冪等操作的特點是其任意多次執行所產生的影響均與一次執行的影響相同。冪等函數,或冪等方法,是指可以使用相同參數重覆執行,並能獲得相同結果的函數。這些函數不會影響系統狀態,也不用擔心重覆執行會對系統造成改變。例如,“getUsername()和setTrue()”函數就是一個冪等函數. 

更複雜的操作冪等保證是利用唯一交易號(流水號)實現. 

我的理解:冪等就是一個操作,不論執行多少次,產生的效果和返回的結果都是一樣的 

一,正式開始了

現在我們們要做一個點擊按鈕之後等待後臺返回之後才可以再次請求方法,其他的重覆請求直接進行攔截

在這裡我使用攔截器進行實現(也可以使用中間件來實現),主要就是以AOP(切麵編程是面向對象的優化),將一些緊密的業務進行切開,在中間進行自己的一些邏輯處理

主要的實現思路就是使用toekn+Redis緩存進行(當我們訪問某個方法的時候給用戶的客戶端存取一個cookie)cookie裡面主要是存的toekn,當我們訪問介面的時候一定要帶上有效的

token才能訪問方法或者控制器。

客戶端訪問方法的時候存token到Redis裡面,當請求方法的時候帶上token,攔截器裡面判斷是不是存放在Redis裡面的token如果不是的直接攔截返回,如果帶上的是有效的token刪除舊token

生成一個新的token存放在cookie裡面,存到Redis,給第二次請求發放token。

代碼理解:

 

//視圖頁面
    public partial class HomeController : Controller
    {
        private readonly RedisHelp cache = new RedisHelp();
        /// <summary>
        /// 首頁  獲取token
        /// </summary>
        /// <returns></returns>
        [NoSign]
        public IActionResult Index()
        {
            string token = Guid.NewGuid().ToString();
            HttpContext.Response.Cookies.Append("token", token);
            cache.SetValue("token", token);
            return View();
        }
    }

 

當瀏覽器訪問這個視圖的時候給他發放一個token。

這裡存在cooke的好處就是,下一次請求會直接帶上上一次發放的Toekn,我們在前臺就不需要去做任何操作了,這樣攔截器才能算上是一個獨立的模塊。

我們需要訪問這個介面,保證同時點擊的時候只能有一次

 /// <summary>
    /// 介面控制器
    /// </summary>
    public partial class HomeController : Controller
    {
        /// <summary>
        /// 接受提交請求
        /// </summary>
        /// <returns></returns>
        public JsonResult Submit()
        {
            ResponseJson responseJson = new ResponseJson();
            responseJson.msg = "更新了token";
            return Json(responseJson);
        }
    }

下麵就是攔截器的代碼

    /// <summary>
    /// 適合全局的
    /// </summary>
    public class SignFilter : ActionFilterAttribute
    {
        private RedisHelp cache = new RedisHelp();
        /// <summary>
        /// 請求之前
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            // 判斷是否檢查登陸
            var noNeedCheck = false;
            if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
            {
                noNeedCheck = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true)
                  .Any(a => a.GetType().Equals(typeof(NoSignAttribute)));
            }
            if (noNeedCheck)return;

            ResponseJson responseJson = new ResponseJson();
            var token = context.HttpContext.Request.Cookies["token"];
            #region 判斷數據有效性
            if (string.IsNullOrWhiteSpace(token))
            {
                responseJson.msg = "toekn不能空";
                context.Result = new JsonResult(responseJson);
                return;
            } else if (cache.GetValue("token") ==null) {
                responseJson.msg = "toekn不能空";
                context.Result = new JsonResult(responseJson);
                return;
            } else if (!cache.DeleteKey("token")) {
                responseJson.msg = "token已不存在";
                context.Result = new JsonResult(responseJson);
                return;
            }
            #endregion
            base.OnActionExecuting(context);
        }

        /// <summary>
        /// 請求過了之後,在去分發token
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            //隨機值
            string redisToken = Guid.NewGuid().ToString() + new Random().Next(100000, 99999999);
            context.HttpContext.Response.Cookies.Append("token", redisToken);
            //初使化並設置Cookie的名稱
            cache.SetValue("token", redisToken);
        }
    }

    /// <summary>
    /// 不需要登陸的地方加個特性
    /// </summary>
    public class NoSignAttribute : ActionFilterAttribute { }

 

 

 

 

 

但是這個只適合於個人在點擊的時候的,下次我分享一下多人的模式。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 場景 Winform控制項-DevExpress18下載安裝註冊以及在VS中使用: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/100061243 DevExpress的TreeList怎樣設置數據源,從實例入手: https:/ ...
  • 場景 Winform控制項-DevExpress18下載安裝註冊以及在VS中使用: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/100061243 在上面已經實現DevExpress的安裝之後,拖拽一個TreeList,然後怎樣給 ...
  • 前言: 通過Fiddler抓取瀏覽器請求數據,相信大家已經都會用了,我們知道Fiddler是通過在本機計算器添加一個預設的代理伺服器來實現的抓包數據的,埠號為:8888。 其實當我們打開Fiddler的設置也可以看到: 然後查看本地計算器的網路代理設置: 基於上面的原理,Fiddler就實現了經過 ...
  • 在項目視圖中,找到-》輸出 視窗,在視窗中選擇ASP.NET Core Web伺服器,調試項目即可看到執行的sql語句 ...
  • 點這裡進入ABP進階教程目錄 我們嘗試在新增/編輯界面增加一個下拉框用來代替輸入框編輯Status 添加實體 打開領域層(即JD.CRS.Core)的Entitys目錄 //用以存放實體對象添加一個類StatusCode.cs //狀態信息 更新模型 更新查詢視圖模型 打開展示層(即JD.CRS.W ...
  • 點這裡進入ABP進階教程目錄 在功能按鈕區增加一個自定義按鈕 - Add(創建課程) 添加按鈕 打開展示層(即JD.CRS.Web.Mvc)的\wwwroot\view-resources\Views\Course\Index.js //用以存放Course查詢相關腳本 自帶按鈕已有五個我們再添加一 ...
  • 簡述 我們做軟體工作的雖然每天都離不開網路,可網路協議細節卻不是每個人都會接觸和深入瞭解。我今天就來和大家一起學習下Socket,並寫一個簡單的聊天程式。 一些基礎類 首先我們每天打開瀏覽器訪問網頁信息都是使用的HTTP/HTTPS協議,而HTTP是通過的TCP建立的連接。TCP底層又是通過的Soc ...
  • 關鍵字:流程未來節點處理人 工作流快速開發平臺 工作流流設計 業務流程管理 asp.net 開源工作流 業務背景:一個流程在啟動起來後,是可以對一些節點計算出來處理人是誰,流程的走向。對於另外一些節點處理人有可能需要相關的人員調整的。在一些審批的環境下,需要把能夠計算出來的節點處理人在發起時計算出來... ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...