How to throttle requests in a Web Api?

后端 未结 7 524
深忆病人
深忆病人 2020-11-30 17:45

I\'m trying to implement request throttling via the following:

Best way to implement request throttling in ASP.NET MVC?

I\'ve pulled that code into my solut

7条回答
  •  伪装坚强ぢ
    2020-11-30 18:40

    It is very easily solved in .NET Core. In this case, I used IMemoryCache, which is 'in-memory per service'. However, if you want it based on Redis e.g. just change the interface to IDistributedCache… (make sure you configure Redis of course)

    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Filters;
    using Microsoft.Extensions.Caching.Distributed;
    using Microsoft.Extensions.Caching.Memory;
    using System;
    using System.Net;
    
    namespace My.ActionFilters
    {
        /// 
        /// Decorates any MVC route that needs to have client requests limited by time.
        /// 
        /// 
        /// Uses the current System.Web.Caching.Cache to store each client request to the decorated route.
        /// 
        [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
        public class ThrottleFilterAttribute : ActionFilterAttribute
        {
            public ThrottleFilterAttribute()
            {
    
            }
            /// 
            /// A unique name for this Throttle.
            /// 
            /// 
            /// We'll be inserting a Cache record based on this name and client IP, e.g. "Name-192.168.0.1"
            /// 
            public string Name { get; set; }
    
            /// 
            /// The number of seconds clients must wait before executing this decorated route again.
            /// 
            public int Seconds { get; set; }
    
            /// 
            /// A text message that will be sent to the client upon throttling.  You can include the token {n} to
            /// show this.Seconds in the message, e.g. "Wait {n} seconds before trying again".
            /// 
            public string Message { get; set; }
    
            public override void OnActionExecuting(ActionExecutingContext c)
            {
                 var memCache = (IMemoryCache)c.HttpContext.RequestServices.GetService(typeof(IMemoryCache));
            var testProxy = c.HttpContext.Request.Headers.ContainsKey("X-Forwarded-For");
            var key = 0;
            if (testProxy)
            {
                var ipAddress = IPAddress.TryParse(c.HttpContext.Request.Headers["X-Forwarded-For"], out IPAddress realClient);
                if (ipAddress)
                {
                    key = realClient.GetHashCode(); 
                }
            }
            if (key != 0)
            {
                key = c.HttpContext.Connection.RemoteIpAddress.GetHashCode();
            }
             memCache.TryGetValue(key, out bool forbidExecute);
    
            memCache.Set(key, true, new MemoryCacheEntryOptions() { SlidingExpiration = TimeSpan.FromMilliseconds(Milliseconds) });
    
            if (forbidExecute)
            {
                if (String.IsNullOrEmpty(Message))
                    Message = $"You may only perform this action every {Milliseconds}ms.";
    
                c.Result = new ContentResult { Content = Message, ContentType = "text/plain" };
                // see 409 - http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
                c.HttpContext.Response.StatusCode = StatusCodes.Status409Conflict;
            }
        }
        }
    }
    

提交回复
热议问题