| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- using System;
- using System.Web;
- namespace SiteCore
- {
- public class FrequencyControler
- {
- /// <summary>
- /// 访问控制器名称,用于区分其它控制器,支持多个控制器
- /// </summary>
- private string Name { get; set; }
- /// <summary>
- /// 限定时长
- /// </summary>
- private int Seconds { get; set; }
- /// <summary>
- /// 限定次数
- /// </summary>
- private int Times { get; set; }
- public readonly int MAX_TIMES = 100;
- #region 私有方法
- private string SessionNameDatelist
- {
- get { return String.Format("fc.{0}.datelist", Name); }
- }
- private string SessionNameDatepos
- {
- get { return String.Format("fc.{0}.datepos", Name); }
- }
- /// <summary>
- /// 取得用于保存每次访问时间点的数组(做队列用)
- /// </summary>
- /// <returns></returns>
- private long[] GetDateList()
- {
- if (HttpContext.Current.Session[SessionNameDatelist] == null)
- {
- HttpContext.Current.Session[SessionNameDatelist] = new long[MAX_TIMES];
- }
- return (long[])HttpContext.Current.Session[SessionNameDatelist];
- }
- /// <summary>
- /// 获取时间记录位置,相当于当前队列位置
- /// </summary>
- /// <returns></returns>
- private int GetDatepos()
- {
- if (HttpContext.Current.Session[SessionNameDatepos] == null)
- {
- HttpContext.Current.Session[SessionNameDatepos] = 0;
- }
- return (int)HttpContext.Current.Session[SessionNameDatepos];
- }
- /// <summary>
- /// 设置时间记录位置,相当于当前队列位置
- /// </summary>
- /// <param name="pos"></param>
- private void SetDatepos(int pos)
- {
- HttpContext.Current.Session[SessionNameDatepos] = pos;
- }
- #endregion
- /// <summary>
- /// 构造访问检测器,限定指定时间内最多请求次数
- /// </summary>
- /// <param name="name">名称</param>
- /// <param name="seconds">限定时间范围(秒数)</param>
- /// <param name="times">限定次数</param>
- public FrequencyControler(string name, int seconds, int times)
- {
- Name = name;
- Seconds = seconds;
- Times = times;
- if (times > MAX_TIMES) throw new Exception("限定次数设置值超出上限!");
- }
- /// <summary>
- /// 记录一次访问,在时间点数组的下一个位置(按最大长度循环覆盖存储)
- /// </summary>
- public void Record()
- {
- long[] ds = GetDateList();
- int pos = GetDatepos();
- pos = (pos + 1) % ds.Length;
- ds[pos] = DateTime.Now.Ticks;
- SetDatepos(pos);
- }
- /// <summary>
- /// 判断是否达到访问限制(并默认记录一次请求)
- /// </summary>
- /// <returns></returns>
- public bool IsTooFrequently()
- {
- return IsTooFrequently(true);
- }
- /// <summary>
- /// 判断是否达到访问限制(主要外部使用功能)
- /// </summary>
- /// <param name="isRecord">是否包含本次请求,为true时,会先记录一次请求再判断</param>
- /// <returns></returns>
- public bool IsTooFrequently(bool isRecord)
- {
- if (isRecord) Record();
- long[] ds = GetDateList();
- int pos = GetDatepos();
- // 取得之前 限定次数 位置的时间点与最后的时间点比较,
- // 如果之前的访问次数还没有达到限定次数则忽略
- int pre_pos = (pos + ds.Length - Times + 1) % ds.Length;
- long pre_ticks = ds[pre_pos];
- long now_ticks = ds[pos];
- // 如果访问的次烤都还没有达到限定次数,pre_ticks 必定为0,所以大于0时才进行比较
- if (pre_ticks > 0)
- {
- TimeSpan span = new TimeSpan(now_ticks - pre_ticks);
- if (span.TotalSeconds <= Seconds)
- {
- return true;
- }
- }
- return false;
- }
- }
- }
|