限制單一使用者同時間的大量 web request
有些網站,例如AI繪圖,因為單一 request 會花較長時間,所以會限制使用者不能重覆送 request,或是在一個 request 結束後,在一定時間內不能再送第二次,本篇文章會提出一個概念性想法。
它的設定也很直覺,程式碼如下:
public class RequestManager
{
private static RequestManager instance;
public static RequestManager Instance
{
get
{
if (instance == null)
{
instance = new RequestManager();
}
return instance;
}
}
private RequestManager()
{
_requestDictionary = new ConcurrentDictionary<string, RequestModel>();
_waitingtimeDictionary = new ConcurrentDictionary<string, DateTime>();
}
private ConcurrentDictionary<string, RequestModel> _requestDictionary;
private ConcurrentDictionary<string, DateTime> _waitingtimeDictionary;
private const int waitingseconds = 10;
public bool CheckTimespan(string token)
{
if (_waitingtimeDictionary.ContainsKey(token))
{
DateTime previousTime = _waitingtimeDictionary[token];
DateTime dt = DateTime.Now;
TimeSpan timeOffset = dt - previousTime;
if (timeOffset.Seconds > waitingseconds)
{
_waitingtimeDictionary.TryRemove(token, out dt);
return true;
}
else
{
return false;
}
}
return true;
}
public bool ReceiveRequest(RequestModel requestModel)
{
if (!_requestDictionary.ContainsKey(requestModel.Token))
{
_requestDictionary.TryAdd(requestModel.Token, requestModel);
_waitingtimeDictionary.TryAdd(requestModel.Token, DateTime.Now);
return true;
}
if (_waitingtimeDictionary.ContainsKey(requestModel.Token))
{
return CheckTimespan(requestModel.Token);
}
return true;
}
public bool CanSendRequest(string token)
{
return CheckTimespan(token);
}
public void RemoveRequest(string token)
{
_requestDictionary.TryRemove(token, out RequestModel requestModel);
_waitingtimeDictionary.TryRemove(token, out DateTime dt);
}
}
主要的概念在於宣告兩個 Dictionary,一個儲存 request,一個儲存收到 request 的時間。
public bool ReceiveRequest(RequestModel requestModel)
{
if (!_requestDictionary.ContainsKey(requestModel.Token))
{
_requestDictionary.TryAdd(requestModel.Token, requestModel);
_waitingtimeDictionary.TryAdd(requestModel.Token, DateTime.Now);
return true;
}
if (_waitingtimeDictionary.ContainsKey(requestModel.Token))
{
return CheckTimespan(requestModel.Token);
}
return true;
}
而在 request 結束後,把它刪除:
public void RemoveRequest(string token)
{
_requestDictionary.TryRemove(token, out RequestModel requestModel);
_waitingtimeDictionary.TryRemove(token, out DateTime dt);
}
另一個比較重要的就是,檢查時間是否到了:
public bool CheckTimespan(string token)
{
if (_waitingtimeDictionary.ContainsKey(token))
{
DateTime previousTime = _waitingtimeDictionary[token];
DateTime dt = DateTime.Now;
TimeSpan timeOffset = dt - previousTime;
if (timeOffset.Seconds > waitingseconds)
{
_waitingtimeDictionary.TryRemove(token, out dt);
return true;
}
else
{
return false;
}
}
return true;
}