222

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

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

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

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

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

4

3 回答 3

253

这是我们过去一年在 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 :)

于 2009-08-23T08:21:56.053 回答
69

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 millisecondsIP 地址将被阻止,Y milliseconds则将再次允许请求。

于 2009-02-25T04:10:51.770 回答
11

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

于 2008-11-14T20:59:30.623 回答