如果API速率限制超过使用WebApiThrottle - C#Web API,则阻止API请求5分钟

时间:2017-02-23 09:20:10

标签: c# api asp.net-web-api throttling rate-limiting

Web API中的API速率限制有一个非常好的库WebApiThrottle 如Wiki页面所述,我可以根据API调用的授权令牌头来限制API  但是,如果此api速率限制超过,我怎样才能阻止接下来5分钟的api呼叫?此外,并非在接下来的5分钟内任何请求都会重置超出限速的时间。

我检查了代码但找不到此功能。如果有人可以建议,还有其他任何方式吗?

1 个答案:

答案 0 :(得分:2)

目前,我正在使用 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