144 lines
4.9 KiB
C#
144 lines
4.9 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Linq;
|
|||
|
|
using System.Text;
|
|||
|
|
using Newtonsoft.Json;
|
|||
|
|
using System.Web;
|
|||
|
|
|
|||
|
|
namespace Common
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 记录每次(总次数设定上限,超过要求的频率即可)访问的时间,比较当前访问时间与向前指定次数那次的访问时间,如果时间短于规定的时长,则表示已经超过规定时长内访问次数了,即访问过于频繁了。
|
|||
|
|
/// 如:public static FrequencyControler DoFrequency = new FrequencyControler("act", 10, 3);//定义访问控制器允许10秒内3次请求
|
|||
|
|
/// DoFrequency.IsTooFrequently(true)//访问过于频繁!
|
|||
|
|
/// </summary>
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|