首頁 > 後端開發 > Golang > 使用 Redis 對 Golang API 進行速率限制

使用 Redis 對 Golang API 進行速率限制

Barbara Streisand
發布: 2024-11-15 04:28:02
原創
566 人瀏覽過

用更簡單的話來說,速率限制,它是一種限制使用者或客戶端在給定時間範圍內可以向 API 發出請求數量的技術。過去,當您嘗試存取天氣或笑話 API 時,您可能遇到過收到「超出速率限制」訊息的情況。關於為什麼要限制 API 的速率有很多爭論,但一些重要的爭論是合理使用它、確保其安全性、保護資源免於過載等。

在本部落格中,我們將使用 Gin 框架使用 Golang 建立一個 HTTP 伺服器,使用 Redis 對端點應用速率限制功能,並儲存某個時間範圍內 IP 向伺服器發出的請求總數。如果超過我們設定的限制,我們會給出錯誤訊息。

如果你不知道 Gin 和 Redis 是什麼。 Gin 是一個用 Golang 寫的 Web 框架。它有助於創建一個簡單而快速的伺服器,而無需編寫大量程式碼。 Redis 它是一個記憶體中的鍵值資料存儲,可以用作資料庫或快取功能。

先決條件

  • 熟悉 Golang、Gin 和 Redis
  • 一個 Redis 實例(我們可以使用 Docker 或遠端機器)

現在,讓我們開始吧。

要初始化項目,請執行 go mod init ;例如,go mod init github.com/Pradumnasaraf/go-redis。

然後讓我們使用 Gin 框架建立一個簡單的 HTTP 伺服器,然後套用對其進行速率限制的邏輯。您可以複製下面的程式碼。這是非常基本的。當我們點擊 /message 端點時,伺服器將回覆一則訊息。

複製以下程式碼後,執行 go mod tidy 即可自動安裝我們匯入的軟體包。

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/message", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "You can make more requests",
        })
    })
    r.Run(":8081") //listen and serve on localhost:8081
} 
登入後複製
登入後複製

我們可以透過在終端機中執行 go run main.go 來運行伺服器,並在終端機中看到此訊息。

Rate Limiting a Golang API using Redis

要測試它,我們可以存取 localhost:8081/message 我們將在瀏覽器中看到此訊息。

Rate Limiting a Golang API using Redis

現在我們的伺服器正在運行,讓我們為 /message 路由設定速率限制功能。我們將使用 go-redis/redis_rate 套件。感謝這個套件的創建者,我們不需要從頭開始編寫處理和檢查限制的邏輯。它將為我們完成所有繁重的工作。

以下是實現限速功能後的完整程式碼。我們會理解其中的每一點。只是儘早給出完整的程式碼,以避免任何混淆並了解不同部分如何協同工作。

複製程式碼後,執行 go mod tidy 來安裝所有匯入的軟體包。現在讓我們跳轉並理解程式碼(在程式碼片段下方)。

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/message", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "You can make more requests",
        })
    })
    r.Run(":8081") //listen and serve on localhost:8081
} 
登入後複製
登入後複製

我們先直接跳到rateLimiter()函數來理解一下。該函數需要一個參數,即請求的 IP 位址,我們可以透過主函數中的 c.ClientIP() 來取得該位址。如果達到限制,我們將傳回錯誤,否則將其保持為零。大部分程式碼是我們從官方 GitHub 儲存庫中取得的樣板程式碼。這裡需要仔細研究的關鍵功能是 limiter.Allow() 函數。 Addr:取得 Redis 實例的 URL 路徑值。我正在使用 Docker 在本地運行它。您可以使用任何內容,只需確保相應地替換 URL 即可。

package main

import (
    "context"
    "errors"
    "net/http"

    "github.com/gin-gonic/gin"
    "github.com/go-redis/redis_rate/v10"
    "github.com/redis/go-redis/v9"
)

func main() {
    r := gin.Default()
    r.GET("/message", func(c *gin.Context) {
        err := rateLimiter(c.ClientIP())
        if err != nil {
            c.JSON(http.StatusTooManyRequests, gin.H{
                "message": "you have hit the limit",
            })
            return
        }
        c.JSON(http.StatusOK, gin.H{
            "message": "You can make more requests",
        })
    })
    r.Run(":8081")
}

func rateLimiter(clientIP string) error {
    ctx := context.Background()
    rdb := redis.NewClient(&redis.Options{
        Addr: "localhost:6379",
    })

    limiter := redis_rate.NewLimiter(rdb)
    res, err := limiter.Allow(ctx, clientIP, redis_rate.PerMinute(10))
    if err != nil {
        panic(err)
    }
    if res.Remaining == 0 {
        return errors.New("Rate")
    }

    return nil
}
登入後複製

它有三個參數,第一個是 ctx,第二個是 Key,Redis 資料庫的 Key(值的鍵),第三個是限制。因此,函數將 clientIP 位址儲存為鍵,將預設限制儲存為值,並在發出請求時減少它。這種結構的原因是Redis資料庫需要唯一標識和唯一鍵來儲存鍵值對類型的數據,並且每個IP位址都以自己的方式唯一,這就是為什麼我們使用IP位址而不是用戶名,第三個參數redis_rate.PerMinute(10) 可以依照我們的需求進行修改,我們可以設定限制PerSecond, PerHour,等等,並設定括號內的值,表示每分鐘/秒/小時可以發出多少個請求。在我們的例子中,它是每分鐘 10 個。是的,設定就這麼簡單。

最後,我們透過 res.Remaining 檢查是否有剩餘配額。如果它為零,我們將返回錯誤訊息,否則我們將返回 nil。例如,您也可以執行 res.Limit.Rate 來檢查限制率等。您可以嘗試並深入研究它。

現在是 main() 函數:

res, err := limiter.Allow(ctx, clientIP, redis_rate.PerMinute(10))
登入後複製

一切都幾乎一樣。在 /message 路由中,現在每次路由命中時,我們都會呼叫rateLimit()函數並向其傳遞一個 ClientIP 位址,並將傳回值(錯誤)值儲存在 err 變數中。如果發生錯誤,我們將回傳 429,即 http.StatusTooManyRequests,以及一則訊息「message」:「您已達到限制」。如果該人有剩餘限制並且rateLimit()沒有返回錯誤,它將正常工作,就像之前所做的那樣並服務於請求。

這就是所有的解釋。現在讓我們測試一下工作情況。透過執行相同的命令重新運行伺服器。我們將第一次看到之前收到的相同訊息。現在刷新您的瀏覽器 10 次(因為我們設定了每分鐘 10 次的限制),您將在瀏覽器中看到錯誤訊息。

Rate Limiting a Golang API using Redis

我們也可以透過查看終端機中的日誌來驗證這一點。 Gin 提供了很好的開箱即用的登入功能。一分鐘後它將恢復我們的限製配額。

Rate Limiting a Golang API using Redis

本部落格到此結束,我希望您喜歡閱讀,就像我喜歡寫這篇文章一樣。我很高興您能堅持到最後,非常感謝您的支持。我還經常在 X (Twitter) 上談論 Golang 以及其他內容,例如開源和 Docker。你可以在那裡聯絡我。

以上是使用 Redis 對 Golang API 進行速率限制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板