Web API中有一个非常不错的库WebApiThrottle 用于API速率限制。
如Wiki页面所述,我可以基于API调用的授权令牌标头对API进行速率限制。
但是,如果超出此API速率限制,如何在接下来的5分钟内阻止api调用?同样,并不是说在接下来的5分钟之内任何请求都会重置速率限制超出的时间。
我检查了代码,但找不到此功能。如果有人可以提出其他建议?
最佳答案
目前,我正在使用WebApiThrottle的fork并将dll手动添加到解决方案中。 @adamriyadi已在fork中实现了此功能。等待它进入NuGet包。
更新:后来,我使用HttpRuntime.Cache
使用自己的实现来实现API速率限制和阻塞时间。因此,无需添加任何其他库。
public class ThrottleAttribute : ActionFilterAttribute
{
private int _API_RATEQUOTA = 60;
// per x minute value
private int _API_TIMELIMIT = 1;
private int _API_BLOCKDURATION = 5;
private readonly object syncLock = new object();
public override void OnActionExecuting(HttpActionContext actionContext)
{
// Extract access_token or id or ip address to uniquely identify an API call
var access_token = AuthHelper.GetAuthToken(actionContext.Request);
if (access_token != null)
{
string throttleBaseKey = GetThrottleBaseKey(access_token);
string throttleCounterKey = GetThrottleCounterKey(access_token);
lock (syncLock)
{
//add a listner for new api request count
if (HttpRuntime.Cache[throttleBaseKey] == null)
{
// add api unique key.. this cache will get expire after _API_TIMELIMIT
HttpRuntime.Cache.Add(throttleBaseKey,
DateTime.UtcNow,
null,
DateTime.Now.AddMinutes(_API_TIMELIMIT),
Cache.NoSlidingExpiration,
CacheItemPriority.High,
null);
// add count as value for that api.. this cache will get expire after _API_TIMELIMIT
HttpRuntime.Cache.Add(throttleCounterKey,
1,
null,
DateTime.Now.AddMinutes(_API_TIMELIMIT),
Cache.NoSlidingExpiration,
CacheItemPriority.High,
null);
}
else
{
//listener exists for api request count
var current_requests = (int)HttpRuntime.Cache[throttleCounterKey];
if (current_requests < _API_RATEQUOTA)
{
// increase api count
HttpRuntime.Cache.Insert(throttleCounterKey,
current_requests + 1,
null,
DateTime.Now.AddMinutes(_API_TIMELIMIT),
Cache.NoSlidingExpiration,
CacheItemPriority.High,
null);
}
//hit rate limit, wait for another 5 minutes (_API_BLOCKDURATION)
else
{
HttpRuntime.Cache.Insert(throttleBaseKey,
DateTime.UtcNow,
null,
DateTime.Now.AddMinutes(_API_BLOCKDURATION),
Cache.NoSlidingExpiration,
CacheItemPriority.High,
null);
HttpRuntime.Cache.Insert(throttleCounterKey,
current_requests + 1,
null,
DateTime.Now.AddMinutes(_API_BLOCKDURATION),
Cache.NoSlidingExpiration,
CacheItemPriority.High,
null);
Forbidden(actionContext);
}
}
}
}
else
{
BadRequest(actionContext);
}
base.OnActionExecuting(actionContext);
}
private string GetThrottleBaseKey(string app_id)
{
return Identifier.THROTTLE_BASE_IDENTIFIER + app_id;
}
private string GetThrottleCounterKey(string app_id)
{
return Identifier.THROTTLE_COUNTER_IDENTIFIER + app_id;
}
private void BadRequest(HttpActionContext actionContext)
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest);
}
private void Forbidden(HttpActionContext actionContext)
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden, "Application Rate Limit Exceeded");
}
}
public static class Identifier
{
public static readonly string THROTTLE_BASE_IDENTIFIER = "LA_THROTTLE_BASE_";
public static readonly string THROTTLE_COUNTER_IDENTIFIER = "LA_THROTTLE_COUNT_";
}
现在使用
[ThrottleAttribute]
装饰所需的API