问题描述
那是我使用Redis的课程:
public class RateLimitMiddleware
{
private readonly RequestDelegate _next;
private readonly IConnectionMultiplexer _connectionMultiplexer;
private readonly Options _options;
public RateLimitMiddleware(RequestDelegate next,IConnectionMultiplexer connectionMultiplexer,Options options)
{
if (next == null)
{
throw new ArgumentNullException(nameof(next));
}
if (connectionMultiplexer == null)
{
throw new ArgumentNullException(nameof(connectionMultiplexer));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
_next = next;
_connectionMultiplexer = connectionMultiplexer;
_options = options;
}
public async Task Invoke(HttpContext context)
{
var requestsKeyStore = _connectionMultiplexer.GetDatabase();
var consumerIP = context.Connection.RemoteIpAddress.ToString();
var consumerKey = $"consumer.throttle#{consumerIP}";
var requestKeyVal = await requestsKeyStore.HashIncrementAsync(consumerKey,1);
if (requestKeyVal == 1)
{
await requestsKeyStore.KeyExpireAsync(
consumerKey,_options.RateLimitKeyExpire,CommandFlags.FireAndForget);
}
else if (requestKeyVal > _options.RateLimit)
{
context.Response.StatusCode = StatusCodes.Status429TooManyRequests;
using (var writer = new StreamWriter(context.Response.Body))
{
await writer.WriteAsync("Too many requests.");
}
return;
}
await _next(context);
}
}
我正在尝试通过NSubstitute进行测试:
public async Task CheckRateLimit_Should_Fail_On_Too_Much_Requests()
{
var context = new DefaultHttpContext();
context.Connection.RemoteIpAddress = IPAddress.Parse("127.0.0.1");
var ip = context.Connection.RemoteIpAddress.ToString();
var _connectionMultiplexer = Substitute.For<IConnectionMultiplexer>();
_connectionMultiplexer.IsConnected.Returns(false);
var multiplexerDb = Substitute.For<IDatabase>();
_connectionMultiplexer
.GetDatabase(Arg.Any<Int32>(),Arg.Any<Object>()).Returns(multiplexerDb);
var logger = Substitute.For<ILogger<RateLimitMiddleware>>();
var middleware = new RateLimitMiddleware(
innerHttpContext => Task.CompletedTask,_connectionMultiplexer,_options,logger
);
var startMSecond = DateTime.Now.TimeOfDay.TotalMilliseconds;
var curMSecond = startMSecond;
var count = 0;
while ((curMSecond - startMSecond) < 1000 && count <= _options.RateLimit)
{
await middleware.Invoke(context);
curMSecond = DateTime.Now.TimeOfDay.TotalMilliseconds;
count++;
}
Assert.AreEqual(429,context.Response.StatusCode);
}
我在测试类中将_options.RateLimit设置为2。因此,在我的while循环中,我每秒发送2个以上的请求,因此应该获得429个响应。
当我没有模拟IConnectionMultiplexer并使用localhost连接到Redis时,它起作用了。现在不是。调试后,我知道在对中间件的每个请求中,调用它都会获得没有任何键的新的clear redis数据库。因此,假设即使使用相同的密钥,每个请求都是新的。 我在做什么错了?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)