Cách tốt nhất để thực hiện điều chỉnh yêu cầu trong ASP.NET MVC?


212

Chúng tôi đang thử nghiệm nhiều cách khác nhau để điều tiết hành động của người dùng trong một khoảng thời gian nhất định :

  • Giới hạn câu hỏi / câu trả lời
  • Hạn chế chỉnh sửa
  • Giới hạn truy xuất nguồn cấp dữ liệu

Hiện tại, chúng tôi đang sử dụng Cache để chỉ cần chèn một bản ghi hoạt động của người dùng - nếu bản ghi đó tồn tại nếu / khi người dùng thực hiện cùng một hoạt động, chúng tôi sẽ điều tiết.

Việc sử dụng Cache tự động cung cấp cho chúng tôi việc dọn dẹp dữ liệu và cửa sổ hoạt động trượt của người dùng, nhưng quy mô của nó có thể là một vấn đề.

Một số cách khác để đảm bảo rằng các yêu cầu / hành động của người dùng có thể được điều chỉnh một cách hiệu quả (nhấn mạnh vào sự ổn định) là gì?


Bạn đang cố gắng giới hạn mỗi người dùng hoặc mỗi câu hỏi? Nếu mỗi người dùng, có thể sử dụng phiên, đó sẽ là một bộ nhỏ hơn.
Greg Ogle

1
Mỗi người dùng, nhưng chúng tôi không thể sử dụng Phiên, vì điều đó yêu cầu cookie - hiện tại chúng tôi đang giới hạn dựa trên địa chỉ IP.
Jarrod Dixon

1
Ngày nay, hãy xem xét các gói nuget github.com/stefanprodan/MvcThrption cho các trang MVC và github.com/stefanprodan/WebApiThrption cho các yêu cầu api web
Andy

Câu trả lời:


240

Đây là phiên bản chung của những gì chúng tôi đã sử dụng trên Stack Overflow trong năm qua:

/// <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;
        }
    }
}

Sử dụng mẫu:

[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 Cache hoạt động giống như một nhà vô địch ở đây - bằng cách sử dụng nó, bạn sẽ tự động dọn sạch các mục tiết lưu của mình. Và với lưu lượng ngày càng tăng của chúng tôi, chúng tôi không thấy rằng đây là một vấn đề trên máy chủ.

Hãy phản hồi về phương pháp này; Khi chúng tôi thực hiện Stack Overflow tốt hơn, bạn sẽ sửa lỗi Ewok của mình nhanh hơn :)


5
câu hỏi nhanh - bạn đang sử dụng giá trị c.HttpContext.Request.UserhostAddress như một phần của khóa. Là giá trị đó có thể trống hoặc null hoặc tất cả cùng một giá trị? . cho X-Forwarded-For cũng hay cái gì đó?
Pure.Krom

7
@ Pure.Krom - vâng, nó có thể. Khi lấy IP của máy khách, chúng tôi sử dụng chức năng trợ giúp kiểm tra cả biến REMOTE_ADDRHTTP_X_FORWARDED_FORmáy chủ và vệ sinh một cách thích hợp.
Jarrod Dixon

3
@BrettRobi, tôi khá chắc chắn rằng họ có mối quan hệ máy chủ dựa trên địa chỉ IP của người dùng. Vì vậy, họ có thể vẫn sẽ đánh cùng một máy chủ.
mmcdole

4
Đối với những người bạn quan tâm và đã đọc đến đây trong luồng nhận xét ... chúng tôi cuối cùng đã viết các chuyển hướng của riêng mình để xóa khóa bộ đệm tiết lưu trước khi chuyển hướng. Bằng cách này, tất cả các chuyển hướng đều đi qua mã để loại bỏ khóa và không ai trong số chúng kích hoạt thuộc tính Thr Thr.
SLoret

4
Nếu bạn đang tìm kiếm phiên bản API Web này, hãy kiểm tra tại đây: stackoverflow.com/questions/20817300/ Kẻ
Papa Burgundy

68

Microsoft có một tiện ích mở rộng mới cho IIS 7 có tên là Phần mở rộng hạn chế IP động cho IIS 7.0 - Beta.

"Hạn chế IP động cho IIS 7.0 là mô-đun cung cấp bảo vệ chống lại các cuộc tấn công từ chối dịch vụ và bạo lực trên máy chủ web và các trang web. Bảo vệ như vậy được cung cấp bằng cách tạm thời chặn địa chỉ IP của các máy khách HTTP, những người yêu cầu số lượng đồng thời cao hoặc người thực hiện số lượng lớn yêu cầu trong khoảng thời gian nhỏ. " http://learn.iis.net/page.aspx/548/USE-dynamic-ip-restrictions/

Thí dụ:

Nếu bạn đặt tiêu chí để chặn sau X requests in Y millisecondshoặc X concurrent connections in Y millisecondsđịa chỉ IP sẽ bị chặn Y millisecondsthì yêu cầu sẽ được cho phép lại.


1
Bạn có biết nếu nó gây ra bất kỳ vấn đề nào với trình thu thập thông tin như Googlebot không?
Helephant


1
Hiện tại, nó đã được phát hành và đi kèm với IIS kể từ phiên bản 8 - iis.net/learn/get-started/whats-new-in-iis-8/ trộm
Matthew Steeples

Tôi rất thích sử dụng cái này, nhưng nó KHÔNG cho phép bạn điều tiết bằng cách <location>. Đó là mọi yêu cầu cho ứng dụng hoặc không có.
Kasey speakman

Có vẻ không hữu ích nếu các máy chủ web của bạn đứng sau bộ cân bằng tải, vì tất cả lưu lượng truy cập sẽ xuất hiện từ cùng một địa chỉ IP. Trừ khi tôi đang thiếu một cái gì đó rõ ràng ...
Dscoduc

11

Chúng tôi sử dụng kỹ thuật mượn từ URL này http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx , không phải để điều chỉnh, mà cho Từ chối dịch vụ (DOS) của một người nghèo. Đây cũng là dựa trên bộ đệm và có thể tương tự như những gì bạn đang làm. Bạn có điều tiết để ngăn chặn các cuộc tấn công DOS? Bộ định tuyến chắc chắn có thể được sử dụng để giảm DOS; Bạn có nghĩ rằng một bộ định tuyến có thể xử lý điều tiết bạn cần?


1
Đó là khá nhiều những gì chúng tôi đã làm - nhưng nó hoạt động rất tốt :)
Jarrod Dixon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.