如何在 ASP.NET Core 中实现速率限制?

ASP.NET Core 中实现速率限制(Rate Limiting)中间件可以帮助你控制客户端对 API 的请求频率,防止滥用和过载。速率限制通常用于保护服务器资源,确保服务的稳定性和可用性。

ASP.NET Core 本身并没有内置的速率限制中间件,但你可以通过自定义中间件或使用第三方库来实现速率限制。以下是实现速率限制的几种常见方法:


1. 使用自定义中间件实现速率限制

你可以通过自定义中间件来实现速率限制。以下是一个简单的实现示例:

1.1 实现速率限制中间件
复制代码
using Microsoft.AspNetCore.Http;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public class RateLimitingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly int _maxRequests; // 每分钟允许的最大请求数
    private readonly ConcurrentDictionary<string, RateLimiter> _rateLimiters;

    public RateLimitingMiddleware(RequestDelegate next, int maxRequests)
    {
        _next = next;
        _maxRequests = maxRequests;
        _rateLimiters = new ConcurrentDictionary<string, RateLimiter>();
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // 获取客户端的唯一标识(例如 IP 地址)
        var clientId = context.Connection.RemoteIpAddress.ToString();

        // 获取或创建速率限制器
        var rateLimiter = _rateLimiters.GetOrAdd(clientId, _ => new RateLimiter(_maxRequests));

        if (rateLimiter.AllowRequest())
        {
            await _next(context);
        }
        else
        {
            context.Response.StatusCode = StatusCodes.Status429TooManyRequests;
            await context.Response.WriteAsync("请求太多。请稍后再试.");
        }
    }
}

public class RateLimiter
{
    private readonly int _maxRequests;
    private int _requestCount;
    private DateTime _windowStart;

    public RateLimiter(int maxRequests)
    {
        _maxRequests = maxRequests;
        _requestCount = 0;
        _windowStart = DateTime.UtcNow;
    }

    public bool AllowRequest()
    {
        var now = DateTime.UtcNow;

        // 如果当前时间窗口已过期,重置计数器
        if ((now - _windowStart).TotalSeconds > 60)
        {
            _requestCount = 0;
            _windowStart = now;
        }

        // 检查请求是否超出限制
        if (_requestCount < _maxRequests)
        {
            _requestCount++;
            return true;
        }

        return false;
    }
}
1.2 注册中间件

Startup.cs 中注册中间件:

复制代码
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseMiddleware<RateLimitingMiddleware>(10); // 每分钟最多 10个请求

    app.UseRouting();

    app.UseEndpoints(endpoints =>
                     {
                         endpoints.MapControllers();
                     });
}

2. 使用第三方库实现速率限制

如果你不想自己实现速率限制逻辑,可以使用一些现成的第三方库,例如:

2.1 AspNetCoreRateLimit

AspNetCoreRateLimit 是一个流行的 ASP.NET Core 速率限制库,支持 IP 地址、客户端 ID 和端点级别的速率限制。

安装

通过 NuGet 安装:

复制代码
dotnet add package AspNetCoreRateLimit
配置

Startup.cs 中配置速率限制:

复制代码
public void ConfigureServices(IServiceCollection services)
{
    // 添加内存缓存
    services.AddMemoryCache();

    // 配置速率限制
    services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
    services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
    services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
    services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
    services.AddSingleton<IProcessingStrategy, AsyncKeyLockProcessingStrategy>();
    services.AddInMemoryRateLimiting();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseIpRateLimiting();

    app.UseRouting();

    app.UseEndpoints(endpoints =>
                     {
                         endpoints.MapControllers();
                     });
}
配置文件

appsettings.json 中添加速率限制配置:

复制代码
{
    "IpRateLimiting": {
        "EnableEndpointRateLimiting": true,
        "StackBlockedRequests": false,
        "RealIpHeader": "X-Real-IP",
        "ClientIdHeader": "X-ClientId",
        "GeneralRules": [
            {
                "Endpoint": "*",
                "Period": "1m",
                "Limit": 10
                }
        ]
    }
}

3. 使用分布式缓存实现速率限制

如果你的应用是分布式的(例如部署在 Kubernetes 或多个服务器上),可以使用分布式缓存(如 Redis)来实现速率限制。

3.1 使用 Redis 实现速率限制

你可以使用 Redis 来存储每个客户端的请求计数。以下是一个简单的示例:

复制代码
using Microsoft.AspNetCore.Http;
using StackExchange.Redis;
using System.Threading.Tasks;

public class RedisRateLimitingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly int _maxRequests;
    private readonly ConnectionMultiplexer _redis;

    public RedisRateLimitingMiddleware(RequestDelegate next, int maxRequests, ConnectionMultiplexer redis)
    {
        _next = next;
        _maxRequests = maxRequests;
        _redis = redis;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var clientId = context.Connection.RemoteIpAddress.ToString();
        var db = _redis.GetDatabase();

        var key = $"rate_limit:{clientId}";
        var requestCount = await db.StringIncrementAsync(key);

        if (requestCount == 1)
        {
            await db.KeyExpireAsync(key, TimeSpan.FromMinutes(1));
        }

        if (requestCount > _maxRequests)
        {
            context.Response.StatusCode = StatusCodes.Status429TooManyRequests;
            await context.Response.WriteAsync("请求太多。请稍后再试.");
        }
        else
        {
            await _next(context);
        }
    }
}
3.2 注册中间件

Startup.cs 中注册中间件:

复制代码
public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<ConnectionMultiplexer>(ConnectionMultiplexer.Connect("localhost:6379"));
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseMiddleware<RedisRateLimitingMiddleware>(10); // 每分钟最多 10个请求

    app.UseRouting();

    app.UseEndpoints(endpoints =>
                     {
                         endpoints.MapControllers();
                     });
}

4. 总结

ASP.NET Core 中实现速率限制有多种方式:

  • 自定义中间件:适合简单的场景,但需要自己实现逻辑。
  • 第三方库:如 AspNetCoreRateLimit,提供了更强大的功能和灵活性。
  • 分布式缓存:如 Redis,适合分布式环境。

根据你的需求选择合适的方式,确保你的 API 能够有效防止滥用和过载。

关注灵活就业新业态,关注公账号:贤才宝(贤才宝https://www.51xcbw.com

相关推荐
消失的旧时光-19431 小时前
Spring Boot 工程化进阶:统一返回 + 全局异常 + AOP 通用工具包
java·spring boot·后端·aop·自定义注解
追风筝的人er2 小时前
SpringBoot+Vue3 企业考勤如何处理法定假期?节假日方案、调休补班与工作日判断链路拆解
前端·vue.js·后端
金銀銅鐵3 小时前
[git] 如何丢弃对一个文件的改动?
git·后端
橘子海全栈攻城狮3 小时前
【最新源码】养老院系统管理A013
java·spring boot·后端·web安全·微信小程序
smallyoung3 小时前
具有反思能力的 Agentic RAG 实战:用 LangChain4j 实现 CRAG 纠错检索
人工智能·后端
EthanYuan3 小时前
💡RAG实践:从云知识库迁移到PostgreSQL ,并使用PGVector实现向量存储
后端
直奔標竿4 小时前
Java开发者AI转型第二十六课!Spring AI 个人知识库实战(五)——联网搜索增强实战
java·开发语言·人工智能·spring boot·后端·spring
等风来_shy4 小时前
如何写好一个 Skill
后端
ailab4 小时前
研发人员如何写好 AI 提示词:从“问问题”到“驱动研发闭环”
后端
ltl5 小时前
【大模型基础设施工程】25:大模型基础设施未来
后端