.NET Redis限制接口请求频率 滑动窗口算法

在.NET中使用Redis来限制接口请求频率(每10秒只允许请求一次)

NuGet setup

StackExchange.Redis

实现速率限制逻辑

在控制器或服务层中,编写Redis速率限制计数器。
设置Redis键

为每个用户或每个IP地址设置一个唯一的键。这个键将用于存储最后一次请求的时间戳和/请求计数。
检查时间戳

当请求到达时,从Redis中获取该键的值(时间戳)。如果键不存在或时间戳超过10秒,则允许请求并更新键的值(设置为当前时间戳)。
处理超过速率的请求

如果时间戳在10秒内,则拒绝或限制该请求(返回限制状态码)。

csharp 复制代码
   private static readonly Lazy<ConnectionMultiplexer> LazyConnection = new Lazy<ConnectionMultiplexer>(() =>
   {
       // 配置Redis连接字符串 "localhost,abortConnect=false"  
       return ConnectionMultiplexer.Connect("localhost:6379");
   });

   private static ConnectionMultiplexer Connection => LazyConnection.Value;

   private static IDatabase Db => Connection.GetDatabase();

   public async Task<ActionResult> MyAction()
   {

       IPAddress clientIpAddress = HttpContext.Connection.RemoteIpAddress;
       string ipAddress = clientIpAddress.ToString();
       string redisKey = $"rate-limit:{ipAddress}"; // 构建Redis键名  
  
       // 获取当前时间戳(可以是Unix时间戳或任何你选择的格式)  
       long currentTimestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();

       // 尝试从Redis获取时间戳  
       var redisValue = await Db.StringGetAsync(redisKey);
       long lastTimestamp = redisValue.HasValue ? (long)redisValue : 0;

       // 检查是否超过10秒  
       if (currentTimestamp - lastTimestamp >= 10)
       {
           // 如果超过10秒,则允许请求并更新Redis键  
           await Db.StringSetAsync(redisKey, currentTimestamp, TimeSpan.FromSeconds(10)); // 设置键的过期时间为10秒  
                                                                                        
           return Content("Request allowed.");
       }
       else
       {
           // 如果未超过10秒,则拒绝请求  
           HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.TooManyRequests)
           {
               ReasonPhrase = "Too Many Requests",
               Content = new StringContent("Rate limit exceeded. Please try again later.")
           };
           // 处理请求
           return Content("Please try again later. ");// throw new HttpResponseException(response); // 或者返回自定义的ActionResult  
       }
   }

扩展为参数

csharp 复制代码
MyAction(string p)
//...
string redisKey = $"rate-limit:{p}";

请求

/MyAction?p=2

/MyAction?p=3

滑动窗口算法

滑动窗口算法(Sliding Window Algorithm)是一种用于解决字符串/数组 问题的算法,它通过维护一个窗口(即一个连续的子串或子数组),并在字符串或数组上滑动这个窗口来寻找满足特定条件的子串或子数组。以下是滑动窗口算法的主要内容和特点:

维护窗口 :通过两个指针(左指针和右指针)来定义窗口的边界。
移动窗口 :通过移动右指针来扩展窗口,同时根据问题的要求调整左指针来缩小窗口。
更新信息:在窗口滑动的过程中,根据需要更新一些数据结构(如哈希表)来保存所需的信息。

实现方法
步骤1.初始化 :定义左指针和右指针,并初始化它们的位置。
步骤2.扩展窗口 :向右移动右指针,扩展窗口,同时更新所需的信息(如字符频率的哈希表)。
步骤3.检查条件 :当窗口满足特定条件时,开始收缩窗口。
步骤4.收缩窗口 :向右移动左指针,缩小窗口,同时更新所需的信息。
步骤5.更新最优解 :在收缩窗口的过程中,不断更新最优解(如最长子串、最短子串等)。
重复步骤:重复步骤2到步骤5,直到右指针到达字符串或数组的末尾。

在Redis中维护一个窗口内的请求时间戳列表,而不是仅仅存储最后一次请求的时间戳。移除超过窗口大小的时间戳。检查剩余的时间戳数是否超过了最大请求数 MaxRequests。如果超过,则返回超过的响应;否则,记录当前时间戳并允许请求。

csharp 复制代码
			private const int MaxRequests = 5; // 最大请求数
			private const int WindowSizeInSeconds = 10; // 窗口大小(秒)
			//...

            // 获取Redis中存储的时间戳列表
            var redisValue = await Db.ListRangeAsync(redisKey);
            var timestamps = redisValue.Select(value => (long)value).ToList();

            // 移除窗口之外的时间戳
            timestamps = timestamps.Where(timestamp => currentTimestamp - timestamp <= WindowSizeInSeconds).ToList();

            if (timestamps.Count >= MaxRequests)
            {
                // 如果请求数超过限制,则拒绝请求
                HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.TooManyRequests)
                {
                    ReasonPhrase = "Too Many Requests",
                    Content = new StringContent("Rate limit exceeded. Please try again later.")
                };
                return Content("Please try again later.");
            }
            else
            {
                // 如果请求数未超过限制,则允许请求并记录当前时间戳
                timestamps.Add(currentTimestamp);
                await Db.ListRightPushAsync(redisKey, timestamps.Select(timestamp => (RedisValue)timestamp).ToArray());
                await Db.KeyExpireAsync(redisKey, TimeSpan.FromSeconds(WindowSizeInSeconds)); // 设置键的过期时间为窗口大小

                return Content("Request allowed.");
            }

End

相关推荐
一只小灿灿2 小时前
VB.NET在 Excel 二次开发中的全面应用
.net·excel
码农君莫笑2 小时前
信管通低代码信息管理系统应用平台
linux·数据库·windows·低代码·c#·.net·visual studio
liyongqiangcc9 小时前
了解 ASP.NET Core 中的中间件
.net
Kiros_Jiang12 小时前
开源低代码平台-Microi吾码 打印引擎使用
javascript·开源·json·.net·pip
web1478621072315 小时前
C# .Net Web 路由相关配置
前端·c#·.net
数据的世界011 天前
.NET开发人员学习书籍推荐
学习·.net
paixiaoxin1 天前
CV-OCR经典论文解读|An Empirical Study of Scaling Law for OCR/OCR 缩放定律的实证研究
人工智能·深度学习·机器学习·生成对抗网络·计算机视觉·ocr·.net
1900432 天前
.NET重点
.net
m0_663234012 天前
在 .NET 5.0 运行 .NET 8.0 教程:使用 ASP.NET Core 创建 Web API
前端·asp.net·.net