using Microsoft.AspNetCore.Mvc.Filters;
|
using System.Collections.Concurrent;
|
using System.Text.Json;
|
|
public class ThrottleFilter : IAsyncActionFilter
|
{
|
private static readonly ConcurrentDictionary<string, DateTime> _lastExecutionTimes = new ConcurrentDictionary<string, DateTime>();
|
private readonly int _intervalInSeconds;
|
|
public ThrottleFilter(int intervalInSeconds)
|
{
|
_intervalInSeconds = intervalInSeconds;
|
}
|
|
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
{
|
var actionName = context.ActionDescriptor.DisplayName;
|
|
var parameterString = GenerateParameterString(context.ActionArguments);
|
var key = $"{actionName}_{parameterString}";
|
|
if (_lastExecutionTimes.TryGetValue(key, out var lastExecutionTime))
|
{
|
var elapsedTime = DateTime.Now - lastExecutionTime;
|
if (elapsedTime.TotalSeconds < _intervalInSeconds)
|
{
|
context.Result = new OkObjectResult(new WebResponseContent().Error("请求过于频繁,请稍后再试"));
|
return;
|
}
|
}
|
|
_lastExecutionTimes[key] = DateTime.Now;
|
await next();
|
}
|
|
private string GenerateParameterString(IDictionary<string, object> arguments)
|
{
|
if (arguments == null || arguments.Count == 0)
|
{
|
return "";
|
}
|
|
var paramStrings = new List<string>();
|
foreach (var argument in arguments)
|
{
|
var key = argument.Key;
|
var value = argument.Value;
|
string valueString;
|
|
if (value == null)
|
{
|
valueString = "null";
|
}
|
else if (IsSimpleType(value.GetType()))
|
{
|
valueString = value.ToString();
|
}
|
else
|
{
|
valueString = JsonSerializer.Serialize(value);
|
}
|
|
paramStrings.Add($"{key}={valueString}");
|
}
|
|
return string.Join("&", paramStrings);
|
}
|
|
// 判断类型是否为简单类型
|
private bool IsSimpleType(Type type)
|
{
|
return type.IsPrimitive || type == typeof(string) || type == typeof(decimal);
|
}
|
}
|