Files
Web_CRICS_Server_VS2010_Prod/Common/FrequencyControler.cs
2025-12-11 09:17:16 +08:00

144 lines
4.9 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
}
}