【问题标题】:Best way to implement request throttling in ASP.NET MVC?在 ASP.NET MVC 中实现请求限制的最佳方法?
【发布时间】:2010-09-07 05:34:10
【问题描述】:

我们正在试验在给定时间段内限制用户操作的各种方法:

  • 限制问题/答案帖子
  • 限制编辑
  • 限制提要检索

目前,我们使用缓存来简单地插入用户活动的记录 - 如果该记录存​​在并且/当用户执行相同的活动时,我们会限制。

使用缓存自动为我们提供陈旧数据清理和滑动用户活动窗口,但如何扩展可能是个问题。

还有哪些其他方法可以确保有效限制请求/用户操作(强调稳定性)?

【问题讨论】:

  • 您是要限制每个用户还是每个问题?如果每个用户,可以使用会话,这将是一个较小的集合。
  • 这是每个用户的,但我们不能使用 Session,因为这需要 cookie - 我们目前根据 IP 地址进行限制。
  • 现在,考虑 nuget 包 github.com/stefanprodan/MvcThrottle 用于 MVC 页面,github.com/stefanprodan/WebApiThrottle 用于 Web api 请求

标签: asp.net-mvc throttling


【解决方案1】:

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

【讨论】:

  • 这几乎是我们已经在做的事情 - 但效果很好:)
【解决方案2】:

Microsoft 为 IIS 7 提供了一个新的扩展,称为 IIS 7.0 的动态 IP 限制扩展 - Beta。

“IIS 7.0 的动态 IP 限制是一个模块,可防止拒绝服务和对 Web 服务器和网站的暴力攻击。这种保护是通过暂时阻止数量异常高的 HTTP 客户端的 IP 地址来提供的并发请求或在短时间内发出大量请求的人。” http://learn.iis.net/page.aspx/548/using-dynamic-ip-restrictions/

例子:

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

【讨论】:

  • 您知道它是否会导致 Googlebot 等抓取工具出现问题吗?
  • 它现在已经发布并与 IIS 捆绑在版本 8 - iis.net/learn/get-started/whats-new-in-iis-8/…
  • 我很想用这个,但它不允许你通过<location> 来节流。这是对应用程序的每个请求,或者没有。
  • 如果您的 Web 服务器位于负载平衡器后面,这似乎没有用,因为所有流量似乎都来自同一个 IP 地址。除非我遗漏了一些明显的东西......
【解决方案3】:

这是我们过去一年在 Stack Overflow 上使用的通用版本:

/// <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 :)

【讨论】:

  • 快速问题 - 您使用 c.HttpContext.Request.UserHostAddress 值作为键的一部分。该值是否可能为空或 null 或所有相同的值? (即,如果您使用的是负载均衡器并且它是该机器的 IP .. 不是真正的客户端)就像,代理或负载均衡器(即 BIG IP F5)将相同的数据放在那里,您需要检查为 X-Forwarded-For 还是什么?
  • @Pure.Krome - 是的,它可能是。在检索客户端 IP 时,我们使用一个辅助函数来检查 REMOTE_ADDRHTTP_X_FORWARDED_FOR 服务器变量并进行适当的清理。
  • @BrettRobi,我很确定他们具有基于用户 IP 地址的服务器亲和性。所以他们很可能仍然会访问同一个服务器。
  • 对于那些关心并在评论流中阅读过这篇文章的人......我们最终编写了自己的重定向,在重定向之前清除了油门缓存键。这样所有的重定向都会通过代码来移除键,并且它们都不会触发 Throttle 属性。
  • 如果您正在寻找它的 Web API 版本,请在此处查看:stackoverflow.com/questions/20817300/…
猜你喜欢
  • 2019-02-05
  • 2011-01-12
  • 2010-11-29
  • 1970-01-01
  • 2011-11-10
  • 2010-10-14
  • 1970-01-01
  • 2023-03-18
  • 2010-09-13
相关资源
最近更新 更多