揭秘:一行代码搞定.Net API高并发的烦恼

     高并发下的接口请求重复提交问题 在.Net开发中,我们经常遇到用户疯狂点击同一按钮,或者服务响应慢时重复发送请求,导致数据重复添加或混乱。这不仅浪费资源,更会得到错误的业务结果。如何高效解决这一普遍问题呢?

        常规方案使用分布式锁 面对这问题,分布式锁是一种有效的传统解决方案,可以确保同一时间只有一个请求被处理。但面对众多需要锁定的接口,配置分布式锁无疑是一项繁重的工作。如何优化这一流程?

        今天,我带来了一种简洁高效的方案。透过.Net中间件的强大功能,我们可以用一行代码轻松实现防并发。首先,我们定义一个特性ApiLock,并在中间件中实现基于用户Token的Redis锁定。如此设计,简单实用又易于扩展。

        首先,我们需要创建一个ApiLock得特性,用于判断哪些接口需要执行分布式锁

public class ApiLockAttribute : ValidationAttribute{    public ApiLockAttribute(int maxLockTime = 10, string msg = "正在处理,请稍等,请勿重复提交")    {        MaxLockTime = maxLockTime;        Msg = msg;    }
    public int MaxLockTime { get; set; }    public string Msg { get; set; }}
然后我们需要写一个中间件,如果不了解中间件的小伙伴可以查看下面文章进行学习:
https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0

图片

        我们需要创建一个中间件:

public class ApiLockMiddleware : MiddlewareBase{    public override async Task Invoke(HttpContext context)    {    }}

        然后我们需要再这个中间件里写一写逻辑,我需要通过HttpContext 获取到Token(用户或者客户端),来进行唯一标识的判定。

public class ApiLockMiddleware : MiddlewareBase{    public override async Task Invoke(HttpContext context)    {        //获取请求路由        string url= context.Request.Path.Value.ToLower();    }}

        然后我们需要编写一个获取Endpoint的方法:

private static Endpoint GetEndpoint(HttpContext context){    if (context == null)    {        throw new ArgumentNullException(nameof(context));    }    return context.Features.Get<IEndpointFeature>()?.Endpoint;}

        这个方法用于获取请求的EndPoint来判断是否包含ApiLock的特性

public class ApiLockMiddleware : MiddlewareBase{    public override async Task Invoke(HttpContext context)    {         //获取请求路由         string url= context.Request.Path.Value.ToLower();         var endpoint = GetEndpoint(context);         if (endpoint != null)         {             var apiLock = endpoint.Metadata.GetMetadata<ApiLockAttribute>();             if (apiLock == null)             {                 //没有特性直接走                 await base.Invoke(context);                 return;             }             else             {                   //这里才是我们要写 核心逻辑。我们需要获取token,//然后拼接token和url进行锁定                   using (var scope = _scopeFactory.CreateScope()){              var redisLock = scope.ServiceProvider.GetRequiredService<IRedisLock>();                var expiry = TimeSpan.FromSeconds(apiLock .MaxLockTime);//超时时间,如果内部执行超过expity则会释放锁                var wait = TimeSpan.FromSeconds(3);//获取锁的时候等待的时间                   var retry = TimeSpan.FromSeconds(1);//每隔多少时间请求一次                  string key = $"ApiLock:{用户/客户端Token}:{url}";//锁的key 用户唯一ID+API路由作为锁条件,同一个接口没执行完前不允许执行下一次        using (var redLock = await redisLock.CreateLockAsync(key, expiry, wait, retry))                       {                           if (!redLock.IsAcquired)                           {                               //如果被锁定,则返回特性传入的失败消息      await HandleExceptionAsync(context, new Exception(apiLock.Msg), (int)HttpStatusCode.OK);                               return;                           }                           else                           {                               //没有锁定才继续往后走Controller等业务逻辑                               await base.Invoke(context);                               return;                           }                       }                   }                               }         }    }}

   这里我们的中间件就写完了。我们需要写一个注册的方法:

  public static class ApiLockExtensions  {      /// <summary>      /// 防止重复提交中间件      /// </summary>      /// <param name="builder"></param>      /// <returns></returns>      public static IApplicationBuilder UseApiLock(this IApplicationBuilder builder)      {          if (builder == null)          {              throw new ArgumentNullException(nameof(builder));          }          return builder.UseMiddleware<ApiLockMiddleware>();      }  }

        然后,我们需要再Configure里进行注册:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider){    //……    app.UseApiLock();}

        到这里我们的封装就已经完成了,那么我们改如何使用它呢

[ApiController][Route("api/[controller]/[action]")]public class TestController : ControllerBase{    [HttpPost]    [ApiLock(10,"接口被锁定,请稍后再试")]    public async Task<IActionResult> TestApiLock()    {        await Task.Delay(20000);        return Ok();    }}

        这里也非常简单,我们直接再需要使用锁定的接口上添加ApiLock的特性就可以啦,我再这里对中间件提供了2个参数,分别是锁定的最大时间和锁定后的错误提示。这个大家也可以按照自身业务需求来进行扩展。

        然后我们测试一下这个接口,这个接口里面做了20秒的延迟

图片

        我们可以看到,当我们连续点击2次测试接口时,我们发现第二次调用就会返回被锁定了。

        简洁之美,效率之王 这不仅是一种技术优化,更是一种产品哲学的体现。在追求高效的同时,我们更希望能让开发者从重复的工作中解放出来,将更多的精力投入到创新和业务的核心中去。

        即刻行动起来,用最简洁的代码,解决.Net API的高并发头疼问题吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/689717.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vscode 命令无法执行

以管理员启动powershell 输入set-ExecutionPolicy RemoteSigned yarn : 无法加载文件 D:\node\node_global\yarn.ps1。未对文件 D:\node\node_global\yarn.ps1 进行数字签名。无法在当前系统上运行该脚本。有关运行脚本和设置执行策略的详细信息&#xff0c;请参阅 https:/go…

2024年华为OD机试真题-计算三叉搜索树的高度-Java-OD统一考试(C卷)

题目描述: 定义构造三叉搜索树规则如下: 每个节点都存有一个数,当插入一个新的数时,从根节点向下寻找,直到找到一个合适的空节点插入。 查找的规则是: 1. 如果数小于节点的数减去500,则将数插入节点的左子树 2. 如果数大于节点的数加上500,则将…

影响效果图渲染的因素有哪些?渲染100邀请码1a12

效果图对很多行业是刚需&#xff0c;特别是视觉行业&#xff0c;一张好的效果图非常重要&#xff0c;影响效果图渲染的因素有很多&#xff0c;它们是哪些呢&#xff1f;一起来看看吧。 1、渲染引擎 渲染引擎对效果图的渲染至关重要&#xff0c;目前市面上有很多渲染引擎&#x…

阅读笔记(SOFT COMPUTING 2018)Seam elimination based on Curvelet for image stitching

参考文献&#xff1a; Wang Z, Yang Z. Seam elimination based on Curvelet for image stitching[J]. Soft Computing, 2018: 1-16. 注&#xff1a;SOFT COMPUTING 大类学科小类学科Top期刊综述期刊工程技术 3区 COMPUTER SCIENCE, ARTIFICIAL INTELLIGENCE 计算机&#xf…

6.1.0 MPLS LDP动态分配

手动写静态MPLS的转发路径&#xff0c;不仅不方便管理&#xff0c;同时配置量也非常多&#xff0c;每台设备都需要去做配置。为了方便管理且去除繁琐的配置&#xff0c;就需要使用到LDP动态标签分发协议了。 标签分发协议LDP&#xff08;Label Distribution Protocol&#xff…

供应STM32F103C8T6原装芯片

长期供应各品牌芯片&#xff1a; STM32F103C8T6 AMS1117-3V3 STM32F407VGT6 BSC039N06NS ICE2QR2280G-1 IPA65R310CFD IPP60R120P7 BSC010N04LS BSC011N03LS BSC027N04LS BSC042NE7NS3 BSC050N10NS5 BSC0911ND BSC109N10NS3 BSC320N20NS3 BSZ014NE2…

迈向AI时代:掌握Python编程与ChatGPT的强强联手

文章目录 一、ChatGPT与Python编程的结合二、利用ChatGPT学习Python编程的优势三、如何使用ChatGPT学习Python编程四、学习技巧与建议《码上行动&#xff1a;用ChatGPT学会Python编程》特色内容简介作者简介目录获取方式 随着人工智能技术的飞速发展&#xff0c;编程已经成为了…

【漏洞复现-通达OA】通达OA report_bi存在前台SQL注入漏洞

一、漏洞简介 通达OA(Office Anywhere网络智能办公系统)是由北京通达信科科技有限公司自主研发的协同办公自动化软件,是与中国企业管理实践相结合形成的综合管理办公平台。通达OA为各行业不同规模的众多用户提供信息化管理能力,包括流程审批、行政办公、日常事务、数据统计…

代码随想录算法训练营day24 | 77. 组合

今天开始回溯 回溯的模板。for循环是横向遍历&#xff0c;backtracking为纵向遍历。 回溯法解决的问题都可以抽象为树形结构&#xff0c;树的宽度为集合的大小&#xff0c;树的深度为递归的深度 void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择&#x…

Unity3D Shader 素描风格渲染管线实现详解

前言 在游戏开发中&#xff0c;渲染效果是非常重要的一部分&#xff0c;它可以直接影响游戏的视觉效果和玩家的体验。而素描风格的渲染效果是一种非常独特和有趣的风格&#xff0c;可以为游戏增添一种艺术氛围。在Unity3D中&#xff0c;可以通过编写Shader来实现素描风格的渲染…

java面试

一、java基础篇 1.接口和抽象类的区别 相似点&#xff1a; &#xff08;1&#xff09;接口和抽象类都不能被实例化 &#xff08;2&#xff09;实现接口或继承抽象类的普通子类都必须实现这些抽象方法 不同点&#xff1a; &#xff08;1&#xff09;抽象类可以包含普通方法…

供应STM32F407VGT6芯片

长期供应各品牌芯片&#xff1a; STM32F407VGT6 ADM809LAKSZ-REEL7 MC78M05BDTRKG TOP271EG FDD16AN08A0 LM317MDT-TR ES1C DS90UB947TRGCRQ1 KIA75S393F-RTK MC96F8316SM FNB80560T3 S29AL008J55BFIR22 SS8050D-BU STM32F405RGT6TR IRFS3607TRLPBF MC79M05CDTR…

YOLOv8 | 代码逐行解析(二) | 从yaml文件到模型定义(代码逐行注释,小白必看)

👑欢迎大家订阅我的专栏一起学习YOLO👑 一、本文介绍 本文给大家带来的是YOLOv8项目的解读,之前给大家分析了YOLOv8的项目文件分析,这一篇文章给大家带来的是模型训练从我们的yaml文件定义到模型的定义部分的讲解,我们一般只知道如何去训练模型,和配置yaml文件,但是…

网络安全之信息收集<五>

目录 一.信息收集简介1.什么是信息收集2.信息收集的意义3.信息收集的分类(1)主动信息收集(2)被动信息收集 4.收集的具体信息(1)服务器信息(2)网站信息(3)域名信息(4)管理员信息 二.域名信息收集1.域名介绍2.域名分类3.Whois(1)Whois查询(2)Whois反查 4.子域名收集 一.信息收集简…

C++ 基本算法 快速排序 第k个数

给定一个长度为 n 的整数数列&#xff0c;以及一个整数 k &#xff0c;请用快速选择算法求出数列从小到大排序后的第 k 个数。 输入格式 第一行包含两个整数 n 和 k 。 第二行包含 n 个整数&#xff08;所有整数均在 1∼109 范围内&#xff09;&#xff0c;表示整数数列。 输…

STM32 学习2 库函数控制GPIO输出

STM32 学习2 库函数控制GPIO输出 一、GPIO寄存器介绍1. GPIO简介2. GPIO功能&#xff08;1&#xff09;模式分类&#xff08;2&#xff09;模式设置方法MODE[1:0]&#xff1a;模式控制&#xff0c;用于配置端口引脚的模式&#xff1a;CNF[1:0]&#xff1a;配置引脚输出速度&…

【vue+leaflet】vue项目中使用leaflet绘制室内平面图、leaflet.pm在平面图中绘制点、线、面图层(一)

效果图: 一,插件安装 npm i leaflet --save // 我的版本^1.9.4 npm i leaflet.pm --save // 我的版本^2.2.0附官网链接: leaflet官网: https://leafletjs.com/index.html leaflet.pm官网: https://www.npmjs.com/package/leaflet.pm?activeTabreadme 二,模块引入 因为我…

Android MMKV 接入+ 替换原生 SP + 原生 SP 数据迁移

背景:项目中一直使用的是原生 SP,众所周知,使用原生 SP 存在卡顿性能问题。公司的性能监控平台抓到不少原生 SP 导致的 ANR 问题: java.io.FileDescriptor.sync (FileDescriptor.java) android.os.FileUtils.sync (FileUtils.java:256) android.app.SharedPreferencesImpl.…

CentOS7.6安装RocksDB

一、简介 RocksDB是使用C编写的嵌入式kv存储引擎&#xff0c;其键值均允许使用二进制流。由Facebook基于levelDB开发&#xff0c; 提供向后兼容的levelDB API。 RocksDB针对Flash存储进行优化&#xff0c;延迟极小。RocksDB使用LSM存储引擎&#xff0c;纯C编写。Java版本Rock…

Sora 使用教程,新手小白可用

Sora 使用教程&#xff0c;新手小白可用 参考文章&#xff1a;Sora 使用教程&#xff0c;OpenAI 的文生视频模型 为了在激烈的行业竞争中保持领先地位&#xff0c;OpenAI 在 2024 年 2 月 15 日发布了其革命性的文本至视频转换模型——Sora。这个先进的工具能够将文本描述转化…