ps:下面實例是每隔30秒訪問次數不超過3次緩存
一、Filter:async
using Infrastructure.Log; using Infrastructure.Web; using Lemon.Stats.Model; using System; using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Threading.Tasks; using System.Web.Http.Controllers; using System.Web.Http.Filters; namespace Lemon.Stats.Apis { /// <summary> /// 限制單個IP短期內訪問次數 /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class IPActionFilterAttribute : ActionFilterAttribute { /// <summary> /// 限制單個IP短期內訪問次數 /// </summary> /// <param name="actionContext"></param> public override void OnActionExecuting(HttpActionContext actionContext) { string ip = HttpHelper.GetClientIp(actionContext.Request); //var isValid = IPCacheHelper.CheckIsAble(ip); IPCacheInfoModel ipModel = IPCacheHelper.GetIPLimitInfo(ip); if (!ipModel.IsVisit) { Logger.Warn(string.Format("IP【{0}】被限制了【{1}】次數",ipModel.IP,ipModel.Limit)); actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, "系統正忙,請稍微再試。"); return; } base.OnActionExecuting(actionContext); } } }
二、IPCacheHelper:ide
using Lemon.Stats.Model; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Lemon.Stats.Apis { /// <summary> /// 限制單個IP訪問次數 /// </summary> public class IPCacheHelper { /// <summary> /// IP緩存集合 /// </summary> private static List<IPCacheInfoModel> dataList = new List<IPCacheInfoModel>(); private static object lockObj = new object(); /// <summary> /// 一段時間內,最大請求次數,必須大於等於1 ///</summary> private static int maxTimes = 3; /// <summary> /// 一段時間長度(單位秒),必須大於等於1 /// </summary> private static int partSecond = 30; /// <summary> /// 請求被拒絕是否加入請求次數 /// </summary> private static bool isFailAddIn = false; static IPCacheHelper() { } /// <summary> /// 設置時間,默認maxTimes=3, partSecond=30 /// </summary> /// <param name="_maxTimes">最大請求次數</param> /// <param name="_partSecond">請求單位時間</param> public static void SetTime(int _maxTimes, int _partSecond) { maxTimes = _maxTimes; partSecond = _partSecond; } /// <summary> /// 檢測一段時間內,IP的請求次數是否能夠繼續請求和使用 /// </summary> /// <param name="ip">ip</param> /// <returns></returns> public static bool CheckIsAble(string ip) { lock (lockObj) { var item = dataList.Find(p => p.IP == ip); if (item == null) { item = new IPCacheInfoModel(); item.IP = ip; item.ReqTime.Add(DateTime.Now); dataList.Add(item); return true; } else { if (item.ReqTime.Count > maxTimes) { item.ReqTime.RemoveAt(0); } var nowTime = DateTime.Now; if (isFailAddIn) { #region 請求被拒絕也須要加入當次請求 item.ReqTime.Add(nowTime); if (item.ReqTime.Count >= maxTimes) { if (item.ReqTime[0].AddSeconds(partSecond) > nowTime) { return false; } else { return true; } } else { return true; } #endregion } else { #region 請求被拒絕就不須要加入當次請求了 if (item.ReqTime.Count >= maxTimes) { if (item.ReqTime[0].AddSeconds(partSecond) > nowTime) { return false; } else { item.ReqTime.Add(nowTime); return true; } } else { item.ReqTime.Add(nowTime); return true; } #endregion } } } } /// <summary> /// 檢測一段時間內,IP的請求次數是否能夠繼續請求和使用 /// </summary> /// <param name="ip">ip</param> /// <returns></returns> public static IPCacheInfoModel GetIPLimitInfo(string ip) { lock (lockObj) { var item = dataList.Find(p => p.IP == ip); if (item == null) //IP開始訪問 { item = new IPCacheInfoModel(); item.IP = ip; item.ReqTime.Add(DateTime.Now); dataList.Add(item); item.IsVisit = true; //能夠繼續訪問 return item; } else { if (item.ReqTime.Count > maxTimes) { item.ReqTime.RemoveAt(0); } var nowTime = DateTime.Now; if (isFailAddIn) { #region 請求被拒絕也須要加入當次請求 item.ReqTime.Add(nowTime); if (item.ReqTime.Count >= maxTimes) { if (item.ReqTime[0].AddSeconds(partSecond) > nowTime) { item.Limit++; //限制次數+1 item.IsVisit = false;//不能繼續訪問 return item; } else { item.IsVisit = true; //能夠繼續訪問 return item; //單個IP30秒內 沒有屢次訪問 } } else { item.IsVisit = true; //能夠繼續訪問 return item; //單個IP訪問次數沒有達到max次數 } #endregion } else { #region 請求被拒絕就不須要加入當次請求了 if (item.ReqTime.Count >= maxTimes) { if (item.ReqTime[0].AddSeconds(partSecond) > nowTime) { item.Limit++; //限制次數+1 item.IsVisit = false;//不能繼續訪問 return item; } else { item.ReqTime.Add(nowTime); item.IsVisit = true; //能夠繼續訪問 return item; } } else { item.ReqTime.Add(nowTime); item.IsVisit = true; //能夠繼續訪問 return item; } #endregion } } } } } }
三、IPCacheInfoModel:this
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Lemon.Stats.Model { public class IPCacheInfoModel { /// <summary> /// IP /// </summary> public string IP { get; set; } /// <summary> /// 限制次數 /// </summary> public int Limit { get; set; } /// <summary> /// 是否能夠訪問 /// </summary> public bool IsVisit { get; set; } /// <summary> /// 訪問時間 /// </summary> private List<DateTime> reqTime = new List<DateTime>(); /// <summary> /// 訪問時間 /// </summary> public List<DateTime> ReqTime { get { return this.reqTime; } set { this.reqTime = value; } } } }
四、Action:spa
/// <summary> /// IP,PV(VV),UV,註冊用戶點擊量統計 /// 先執行IPActionFilter過濾器,再執行ChannelActionFilter過濾器 /// 先執行後面的過濾器,再執行前面的過濾器,執行方式倒序執行順序 /// </summary> [ChannelActionFilter, IPActionFilter, RoutePrefix("Stats")] public class StatsController : ApiController { /// <summary> /// 每次頁面點擊都統計數據,直接由客戶端調用 /// Header中加入SecretKey,AppKey,UniqueKey /// </summary> /// <returns></returns> [HttpGet, Route("")] public async Task Get() { } }