2008-08-29 85 views
194

我们在定的时间段用各种方式油门用户操作实验:在ASP.NET MVC中实现请求限制的最佳方法?

  • 极限提问/回答的帖子
  • 限制编辑
  • 限制饲料检索

对于目前,我们使用缓存来简单地插入用户活动记录 - 如果该记录存​​在/当用户执行相同的活动时,我们就进行调​​节。

使用Cache会自动为我们提供了陈旧的数据清洗和用户的滑动活动窗口,但如何将规模可能是一个问题。

确保请求/用户操作可以被有效抑制(强调稳定性)的其他方法是什么?

+0

您是想限制每个用户还是每个问题?如果每个用户,可以使用会话,这将是一个较小的集合。 – 2008-11-02 01:23:53

+1

这是每个用户,但我们无法使用会话,因为这需要cookie - 我们目前正在基于IP地址进行限制。 – 2008-11-13 02:20:59

回答

217

下面是我们一直在使用的堆栈溢出过去一年什么的通用版本:

/// <summary> 
/// Decorates any MVC route that needs to have client requests limited by time. 
/// </summary> 
/// <remarks> 
/// Uses the current System.Web.Caching.Cache to store each client request to the decorated route. 
/// </remarks> 
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] 
public class ThrottleAttribute : ActionFilterAttribute 
{ 
    /// <summary> 
    /// A unique name for this Throttle. 
    /// </summary> 
    /// <remarks> 
    /// We'll be inserting a Cache record based on this name and client IP, e.g. "Name-192.168.0.1" 
    /// </remarks> 
    public string Name { get; set; } 

    /// <summary> 
    /// The number of seconds clients must wait before executing this decorated route again. 
    /// </summary> 
    public int Seconds { get; set; } 

    /// <summary> 
    /// 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". 
    /// </summary> 
    public string Message { get; set; } 

    public override void OnActionExecuting(ActionExecutingContext c) 
    { 
     var key = string.Concat(Name, "-", c.HttpContext.Request.UserHostAddress); 
     var allowExecute = false; 

     if (HttpRuntime.Cache[key] == null) 
     { 
      HttpRuntime.Cache.Add(key, 
       true, // is this the smallest data we can have? 
       null, // no dependencies 
       DateTime.Now.AddSeconds(Seconds), // absolute expiration 
       Cache.NoSlidingExpiration, 
       CacheItemPriority.Low, 
       null); // no callback 

      allowExecute = true; 
     } 

     if (!allowExecute) 
     { 
      if (String.IsNullOrEmpty(Message)) 
       Message = "You may only perform this action every {n} seconds."; 

      c.Result = new ContentResult { Content = Message.Replace("{n}", Seconds.ToString()) }; 
      // see 409 - http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 
      c.HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict; 
     } 
    } 
} 

使用范例:

[Throttle(Name="TestThrottle", Message = "You must wait {n} seconds before accessing this url again.", Seconds = 5)] 
public ActionResult TestThrottle() 
{ 
    return Content("TestThrottle executed"); 
} 

ASP.NET缓存就像一个冠军在这里 - 通过使用它,您可以自动清理油门条目。随着我们日益增长的流量,我们没有看到这是服务器上的问题。

随时就此方法提供反馈;当我们使Stack Overflow更好时,您可以更快地获得Ewok fix :)

9

我们使用这个网址http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx借来的技术,不是为了限制,但对于一个穷人的拒绝服务(D.O.S)。这也是基于缓存的,可能与您正在做的相似。你是否在阻止D.O.S.节流?攻击?路由器当然可以用来减少D.O.S;你认为路由器可以处理你需要的节流吗?

+1

这几乎是我们已经在做的 - 但它的工作效果很好:) – 2009-01-11 05:45:16

67

Microsoft对IIS 7新增了一个名为动态IP限制扩展的扩展,用于IIS 7.0 - Beta。

“为IIS 7.0的动态IP限制是提供针对Web服务器和Web站点上的服务和强力攻击拒绝保护模块。这种保护是由HTTP客户谁做的暂时封锁IP地址提供异常大量的并发请求或者在很短的时间内发出大量请求。“ http://learn.iis.net/page.aspx/548/using-dynamic-ip-restrictions/

实施例:

如果设置的条件来阻止X requests in Y millisecondsX concurrent connections in Y milliseconds的IP地址将被阻止为Y milliseconds然后请求将被再次允许之后。

+1

您是否知道它是否会导致像Googlebot这样的抓取工具出现问题? – Helephant 2013-08-23 13:17:18

相关问题