.NET Core 中如何限制介面請求次數

.NET Core 中如何限制介面請求次數

像 AspNetCoreRateLimit 這種輪子我前面有給大家介紹過,今天就不說了,我們來聊聊背後的原理。

最後更新 2022/7/8 上午6:54
黑哥聊dotNet
預計閱讀 4 分鐘
分類
ASP.NET Core
標籤
.NET C# ASP.NET Core

AspNetCoreRateLimit 這種現成套件我之前有跟大家介紹過,今天就不提了,我們來聊聊背後的原理,歡迎各位大神指正!

像我們常看到的一些 API 請求介面網站:

拿請求國外主要城市的七日介面舉例,非 VIP 只能使用 2000 次,VIP 用戶一天最多請求 10000 次,請求該介面時,必須註冊帳號取得 appid 和密鑰。

那我們根據這個需求,設計一個取得天氣的限流介面。

第一步

驗證登入帳號是否存在,如果不存在,我們拋出不存在錯誤

[HttpPost("GetWeather")]
public IActionResult ApiLimit(WeatherInfor weatherInfor)
{
  if (!_userService.IsValid(weatherInfor.Appid, weatherInfor.Appsecret))
  {
    throw new Exception("帳號或密碼錯誤");
  }
}

第二步

判斷該帳戶是否為 VIP 用戶,如果是 VIP 用戶,則沒有總調用次數限制,只有單日限制次數。像這種單日限制次數、隔天清空的資料,我們肯定用快取來處理比較合理。我們設定每天的 23 點 59 分 59 秒所有請求快取是否有效,這就是快取的絕對過期時間。

那具體業務邏輯就是這樣的:由於用戶的 appid 是唯一的,我們可以把它當作 key 值,調用次數當作 value 值。如果快取不存在我們就新增快取,如果快取存在我們就取得調用次數,如果大於 2000 我們就告訴呼叫端調用次數已用完;如果沒有,我們就從快取中取得調用次數,並將其 +1。

快取類別

public class MemoryCacheHelper
{

    public static MemoryCache _cache = new MemoryCache(new MemoryCacheOptions());

    /// <summary>
    /// 驗證快取項目是否存在
    /// </summary>
    /// <param name="key">快取Key</param>
    /// <returns></returns>
    public static bool Exists(string key)
    {
        if (key == null)
        {
            return false;
        }
        return _cache.TryGetValue(key, out _);
    }

    /// <summary>
    /// 取得快取
    /// </summary>
    /// <param name="key">快取Key</param>
    /// <returns></returns>
    public static object Get(string key)
    {
        if (key == null)
        {
            throw new ArgumentNullException(nameof(key));
        }
        if (!Exists(key))
            throw new ArgumentNullException(nameof(key));


        return _cache.Get(key);
    }

    /// <summary>
    /// 新增快取
    /// </summary>
    /// <param name="key">快取Key</param>
    /// <param name="value">快取Value</param>
    /// <param name="expiresSliding">滑動過期時間(如果在過期時間內有操作,則以當前時間點延長過期時間)</param>
    /// <param name="expiressAbsoulte">絕對過期時間</param>
    /// <returns></returns>
    public static bool AddMemoryCache(string key, object value)
    {
        if (key == null)
        {
            throw new ArgumentNullException(nameof(key));
        }
        if (value == null)
        {
            throw new ArgumentNullException(nameof(value));
        }
        DateTime time = Convert.ToDateTime(DateTime.Now.AddDays(1).ToString("D").ToString()).AddSeconds(-1);
        _cache.Set(key, value, time);
        return Exists(key);
    }
}

業務邏輯

public bool IsLimit(string appId)
{
    if (MemoryCacheHelper.Exists(appId))
    {
        int value = int.Parse(MemoryCacheHelper.Get(appId).ToString());
        if (value > 2000)
            return false;
        else
            value = value + 1;

        MemoryCacheHelper.AddMemoryCache(appId, value);
    }
    else
    {
        MemoryCacheHelper.AddMemoryCache(appId, 1);
    }
    return true;
}

最後

去查詢天氣介面,回傳資料

[HttpPost("GetWeather")]
public IActionResult ApiLimit(WeatherInfor weatherInfor)
{
    if (!_userService.IsValid(weatherInfor.Appid, weatherInfor.Appsecret))
    {
        throw new Exception("帳號或密碼錯誤");
    }
    bool isLimit = false;
    if (_userService.IsVIP(weatherInfor.Appid))
    {
        isLimit= _sqlServices.IsLimit(weatherInfor.Appid);
    }
    else
    {
        isLimit = _memoryCacheServices.IsLimit(weatherInfor.Appid);
    }
    if (isLimit)
    {
        //查詢天氣介面 回傳資料
    }
    else
    {
        throw new Exception("調用次數已用完");
    }
    return Ok("");
}

最後如果大家喜歡我的文章,還麻煩請關注並點個讚,希望 .NET 生態圈越來越好!

繼續探索

延伸閱讀

更多文章