.net Core數據的幕等性

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

一、背景 代碼實例: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 { }

 

 

 

 

 

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

 


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

更多相關文章
  • 場景 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 開源工作流 業務背景:一個流程在啟動起來後,是可以對一些節點計算出來處理人是誰,流程的走向。對於另外一些節點處理人有可能需要相關的人員調整的。在一些審批的環境下,需要把能夠計算出來的節點處理人在發起時計算出來... ...
一周排行
  • 一、直接使用線程的問題每次都要創建Thread對象,並向操作系統申請創建一個線程,這是需要耗費CPU時間和記憶體資源的。無法直接獲取線程函數返回值無法直接捕捉線程函數內發生的異常 使用線程池可以解決第一個問題二、.NET中的線程池 在這裡只簡單的介紹一下ThreadPool,由於TPL的存在,我工作中... ...
  • 上次課程我們新建了管理員的模板頁。 本次我們就完善這個模板頁,順便加入樣式和一些基本的組件,配置好整個項目的UI風格。 一、引入 共用的css和js文件 後端庫用nuget, 前端庫用libman. 右鍵wwwroot文件夾,選擇菜單 Add / Client-Side Library 我們使用ad ...
  • 場景 在使用IIS部署ASP.NET的Web項目時提示: InvalidOperationException:未能映射路徑“/” 註: 博客: https://blog.csdn.net/badao_liumang_qizhi 關註公眾號 霸道的程式猿 獲取編程相關電子書、教程推送與免費下載。 實現 ...
  • 場景 ASP.NET中新建MVC項目並連接SqlServer資料庫實現增刪改查: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/107024544 在上面實現了新建簡單的MVC項目以及連接資料庫實現簡單的增刪改查後怎樣將網站部署到 ...
  • --先給GridView控制項註冊滑鼠按下事件gv.MouseDown += new System.Windows.Forms.MouseEventHandler(this.gv_MouseDown); --在滑鼠按下事件裡面增加滑鼠右鍵判斷,並增加滑鼠右鍵菜單複製單元格功能。 private voi ...
  • 用C#代替Javascript來做Web應用,是有多爽? 今天聊聊 Blazor。 Blazor 是一個 Web UI 框架。這個框架允許開發者使用 C# 來創建可運行於瀏覽器的具有完全交互 UI 的 Web 應用。 可以理解為,這是一個 C# 語言的 Vue / Angular / React,可 ...
  • 場景 ASP.NET中新建Web網站並部署到IIS上(詳細圖文教程): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/107199747 在上面博客中已經將網站部署到了IIS上。 但是如果網站很大,頁面比較多,甚至每個頁面都有不少 ...
  • 從事這麼多年的.NET,這段時間來,學習另外一門技術Python。 購買相關的書籍,不停地看書。 然後在VS安裝Python,然後可以上機練習,編寫代碼...... ...
  • 一個微小的投入就會帶來巨大的突變 集群安全模式 為什麼出現集群安全模式呢? ​ Namenode啟動時,首先將鏡像文件載人記憶體,並執行編輯日誌中的各項操作。一旦在內存中成功建立文件系統元數據的映像,則創建一個新的Fsimage文件和一個空的編輯日誌。此時,** Namenode開始監聽Datanod ...
  • 1. 通過new對象實現反射機制( 對象.getClass() ) 2. 通過路徑實現反射機制( Class.forName("包名.類名") ) 3. 通過類名實現反射機制 ( 類名.Class ) class Student { private int id; String name; prot ...