.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 { }

 

 

 

 

 

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

 


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

更多相關文章
  • 點這裡進入ABP進階教程目錄 效果預覽 至此,ABP進階教程的查詢/分頁/排序/導出/列印示例已完成,效果如下 登錄 首頁 辦公室信息 院系信息 課程信息 教職員信息 學生信息 新增 修改 刪除 查詢 複製 導出 列印 敬請期待下一個系列. ...
  • 點這裡進入ABP進階教程目錄 問題描述 功能按鈕 - 導出PDF,中文信息導出為亂碼。 解決方案 導出PDF是通過pdfmake.js實現的。 檢查發現是pdfmake引用的vfs_fonts.js字體只有一種: Roboto,而Roboto不支持中文。 解決思路是生成一個包含支持中文字體的vfs_ ...
  • 點這裡進入ABP進階教程目錄 問題描述 功能按鈕 - 導出CSV,中文信息導出為亂碼。 解決方案 打開展示層(即JD.CRS.Web.Mvc)的\wwwroot\view-resources\Views\Course\Index.js //用以存放Course查詢相關腳本 找到DataTable/b ...
  • 一、Quartz.NET介紹 Quartz.NET是一個強大、開源、輕量的作業調度框架,是 OpenSymphony 的 Quartz API 的.NET移植,用C#改寫,可用於winform和asp.net mvc、.Net Core應用中。它靈活而不複雜。你能夠用它來為執行一個作業而創建簡單的或 ...
  • 場景 近期囤積了一大批編程教程和電子書資料。至於視頻教程,我一般是看完之後整理成相應的博客進行記錄,一般不會再雲盤中進行存取,因為很占空間。 至於電子書資料,很多,就是得一點點整理歸納。 近期我的公眾號:霸道的程式猿。有人留言說有沒有.NET相關的技術數據,我就大體先整理了一部分,還有一些沒來的及歸 ...
一周排行
  • 場景 在Winfom中可以在頁面上多個按鈕或者右鍵的點擊事件中觸發同一個自定義的委托事件。 實現 在位置一按鈕點擊事件中觸發 string parentPath = System.IO.Directory.GetParent("指定路徑").ToString(); //獲取指定路徑的父級目錄並作為參 ...
  • asp.net 根據html模板導出excel public class ExcelHelper { /// <summary> /// 根據html模板文件生成excel文件 /// </summary> /// <param name="ds">數據源</param> /// <param na ...
  • asp.net 使用NPOI讀取excel文件內容 NPOI下載地址:NPOI public class ExcelHelper { /// <summary> /// 讀取Excel文件數據到DataSet,一個Sheet對應一個DataTable /// </summary> /// <para ...
  • 場景 使用Visual Studio 開發Winform程式,使用SVN進行項目版本管理。 在添加引用時,會出現在A電腦中添加了絕對路徑的引用,在B電腦中就會出現找不到 並且將此引用標識為?的狀態。 註: 博客主頁: https://blog.csdn.net/badao_liumang_qizhi ...
  • asp.net 使用 Application 限制單一登錄 原理:用戶登錄後系統會分配一個與用戶唯一對應的SessionID,將當前用戶ID與其SessionID對應保存在Application中,一旦該用戶在其他地方重覆登錄則Application中保存的SessionID就會被更新,導致當前se ...
  • 當我們的系統時間不正常,比如設置一個日期-1999年9月9日,會引發證書問題。 系統時間不正常-IE有概率能訪問 觸發NavigateError事件,異常代碼INET_E_INVALID_CERTIFICATE -- 這是一個必要不充分條件,系統時間不正常時IE有相關證書異常,更新時間能解決此類異常 ...
  • //加密 public static string GDEncode(string data, string Key) { Key = "12345678"; byte[] byKey = System.Text.ASCIIEncoding.ASCII.GetBytes(Key); byte[] b ...
  • static void CopyFiles() { string sourceDir = @"D:\C\ll"; string destDir = @"D:\LL"; if (!Directory.Exists(destDir)) { Directo... ...
  • //接收的為空時,則表示客戶端下線,跳出迴圈 if (r == 0) { break; }; string str = Encoding.UTF8.GetString(buffer, 0, r); //RemoteEndPoint:可以得到遠程客戶端的IP和埠號。 ShowMsg(socketSe... ...
  • 本文梯子 前言 1、.net core 框架性能測試 2、.net core 執行過程 3、中間件執行過程 4、AOP切麵 5、整體框架結構與資料庫表UML 一、創建第一個Core 1、SDK 安裝 2、新建項目 2、新建項目(3.0SDK) 3、項目整體結構分析 二、重要文件說明 1、Progra ...
x