有時候,當用戶請求一個Controller下的Action,我們希望,在單位時間間隔內,比如每秒,每分鍾,每小時,每天,每星期,限制同一個IP地址對某個Action的請求次數。如何做呢?
stefanprodan的MvcThrottle能很好地解決這個問題,以及其它類型的IP限制問題。在這里:https://github.com/stefanprodan/MvcThrottle
把項目從GitHub下載下來,在本地打開。
找到MvcThrottle類庫,打開ThrottlingFilter這個類,在該類的OnActionExecuting方法中修改如下:
//check if limit is reachedif (rateLimit > 0 && throttleCounter.TotalRequests > rateLimit){//log blocked requestif (Logger != null) Logger.Log(ComputeLogEntry(requestId, identity, throttleCounter, rateLimitPeriod.ToString(), rateLimit, filterContext.HttpContext.Request));//break execution and return 409var message = string.IsNullOrEmpty(QuotaExceededMessage) ?"HTTP request quota exceeded! maximum admitted {0} per {1}" : QuotaExceededMessage;//add status code and retry after x seconds to responsefilterContext.HttpContext.Response.StatusCode = (int)QuotaExceededResponseCode;filterContext.HttpContext.Response.Headers.Set("Retry-After", RetryAfterFrom(throttleCounter.Timestamp, rateLimitPeriod));filterContext.Result = QuotaExceededResult(filterContext.RequestContext,string.Format(message, rateLimit, rateLimitPeriod),QuotaExceededResponseCode,requestId);return;}
把以上替換成
//check if limit is reachedif (rateLimit > 0 && throttleCounter.TotalRequests > rateLimit){filterContext.HttpContext.Response.Redirect("/Error.html");return;}
讓其在超過次數時,跳轉到項目根目錄下的Error.html文件。
生成該類庫,類庫MvcThrottle.dll生成在類庫的bin/Debug文件夾下。
在ASP.NET MVC 4 下創建一個項目。
在項目根目錄下創建一個Library文件夾,把剛才的MvcThrottle.dll拷貝其中。
引用Library文件夾下的MvcThrottle.dll組件。
在App_Start文件夾中,修改FilterConfig類如下:
public class FilterConfig{public static void RegisterGlobalFilters(GlobalFilterCollection filters){var throttleFilter = new ThrottlingFilter{Policy = new ThrottlePolicy(perSecond: 1, perMinute: 10, perHour: 60 * 10, perDay: 600 * 10){IpThrottling = true},Repository = new CacheRepository()};filters.Add(throttleFilter);}}
創建HomeController,編寫如下:
public class HomeController : Controller{public ActionResult Index(){return View();}[EnableThrottling(PerSecond = 2, PerMinute = 5, PerHour = 30, PerDay = 300)]public ActionResult Other(){return View();}[HttpPost][EnableThrottling(PerSecond = 2, PerMinute = 5, PerHour = 30, PerDay = 300)]public ActionResult GetSth(){return Json(new {msg=true});}}
生成解決方案。
報錯了!What Happened?
原來MvcThrottle是ASP.NET MVC 5下開發的。
有辦法。重新打開MvcThrottle項目的類庫,在引用中刪除原來的System.Web.Mvc,重新引用本地ASP.NET MVC4版本,重新引用本地的System.Web.Mvc。
重新生成類庫,重新拷貝到Library文件夾下,成功生成解決方案。
在Home/Index.cshtml視圖中:
@{ViewBag.Title = "Index";Layout = "~/Views/Shared/_Layout.cshtml";}<h2>Index</h2><input type="button" id="btn" value="請求"/>@section scripts{<script type="text/javascript">$(function() {$('#btn').on("click", function() {$.post('@Url.Action("GetSth")',function(data) {if (data.msg) {alert("請求成功一次");} else {alert("請求次數過多");}});});});</script>}
當在單位時間間隔內超過規定次數,就彈出"請求次數過多"提示框。
在Home/Other.cshtml視圖中:
@{ViewBag.Title = "Other";Layout = "~/Views/Shared/_Layout.cshtml";}<h2>Other</h2>
當在單位時間間隔內超過規定次數,就跳轉到預定的Error.html頁了。