using System.Collections.Concurrent; using System.Net; namespace Serein.Proto.HttpApi { /// /// 判断访问接口的频次是否正常 /// public class RequestLimiter { private readonly ConcurrentDictionary> requestHistory = new ConcurrentDictionary>(); private readonly TimeSpan interval; private readonly int maxRequests; public RequestLimiter(int seconds, int maxRequests) { interval = TimeSpan.FromSeconds(seconds); this.maxRequests = maxRequests; } /// /// 判断访问接口的频次是否正常 /// /// public bool AllowRequest(HttpListenerRequest request) { var clientIp = request.RemoteEndPoint.Address.ToString(); var clientPort = request.RemoteEndPoint.Port; var clientKey = clientIp + ":" + clientPort; var now = DateTime.Now; // 尝试从字典中获取请求队列,不存在则创建新的队列 var requests = requestHistory.GetOrAdd(clientKey, new Queue()); lock (requests) { // 移除超出时间间隔的请求记录 while (requests.Count > 0 && now - requests.Peek() > interval) { requests.Dequeue(); } // 如果请求数超过限制,拒绝请求 if (requests.Count >= maxRequests) { return false; } // 添加当前请求时间,并允许请求 requests.Enqueue(now); } return true; } } }