P0 实现请求限流中间件:每分钟60次请求限制,保护第三方API配额

This commit is contained in:
claw_bot 2026-03-11 16:13:27 +00:00
parent 89244fc078
commit e5cf289da1
2 changed files with 71 additions and 0 deletions

View File

@ -0,0 +1,68 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
namespace AssetManager.API.Middleware;
/// <summary>
/// 请求限流中间件限制每个用户的请求频率保护第三方API配额
/// </summary>
public class RateLimitMiddleware
{
private readonly RequestDelegate _next;
private readonly IMemoryCache _cache;
private readonly ILogger<RateLimitMiddleware> _logger;
// 限流配置每个用户每分钟最多请求60次平均1秒1次足够正常使用
private const int Limit = 60;
private const int WindowSeconds = 60;
private const string CacheKeyPrefix = "RateLimit_";
public RateLimitMiddleware(RequestDelegate next, IMemoryCache cache, ILogger<RateLimitMiddleware> logger)
{
_next = next;
_cache = cache;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
// 获取用户ID未登录则用IP地址
var userId = context.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value
?? context.Connection.RemoteIpAddress?.ToString()
?? "anonymous";
var cacheKey = $"{CacheKeyPrefix}{userId}";
// 获取当前窗口的请求计数
var requestCount = _cache.Get<int>(cacheKey);
if (requestCount >= Limit)
{
_logger.LogWarning("用户 {UserId} 请求超过限流限制,当前计数: {Count}", userId, requestCount);
context.Response.StatusCode = StatusCodes.Status429TooManyRequests;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(System.Text.Json.JsonSerializer.Serialize(new
{
code = 429,
message = "请求过于频繁,请稍后再试",
data = (object)null
}));
return;
}
// 计数+1首次访问设置过期时间
if (requestCount == 0)
{
_cache.Set(cacheKey, 1, TimeSpan.FromSeconds(WindowSeconds));
}
else
{
_cache.Set(cacheKey, requestCount + 1, _cache.GetEntry(cacheKey).AbsoluteExpirationRelativeToNow ?? TimeSpan.FromSeconds(WindowSeconds));
}
await _next(context);
}
}

View File

@ -118,6 +118,9 @@ app.Services.InitializeDatabase();
// 全局异常处理中间件(必须放在最前面)
app.UseMiddleware<GlobalExceptionMiddleware>();
// 请求限流中间件限制用户请求频率保护第三方API配额
app.UseMiddleware<RateLimitMiddleware>();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();