首页 > 后端开发 > Golang > 使用 Redis 对 Golang API 进行速率限制

使用 Redis 对 Golang API 进行速率限制

Barbara Streisand
发布: 2024-11-15 04:28:02
原创
567 人浏览过

用更简单的话来说,速率限制,它是一种限制用户或客户端在给定时间范围内可以向 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
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板