Go 如何基于IP限制HTTP访问频率的方法实现
在Golang实战开发的过程中,我们经常会遇到一些这样那样的问题,然后要卡好半天,等问题解决了才发现原来一些细节知识点还是没有掌握好。今天golang学习网就整理分享《Go 如何基于IP限制HTTP访问频率的方法实现》,聊聊HTTP、访问频率,希望可以帮助到正在努力赚钱的你。
如果你运行 HTTP 服务,并且希望限制 HTTP 的访问频率,那么你可以借助一些比较稳定的工具,例如: github.com/didip/tollbooth。不过如果你构建的应用比较简单,也可以自己来实现。
我们可以使用一个现有的 Go 包 x/time/rate。
本课程,我们将创建一个简单的中间件实现基于 IP 限制 HTTP 访问频率。
简单的 HTTP 服务
让我们从创建一个简单的 HTTP 服务开始,它有非常简单的终端。 但是,因为它的访问频率可能非常高,因此我们要为它添加频率限制。
package main
import (
"log"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", okHandler)
if err := http.ListenAndServe(":8888", mux); err != nil {
log.Fatalf("unable to start server: %s", err.Error())
}
}
func okHandler(w http.ResponseWriter, r *http.Request) {
// 某些消耗很高的数据库请求
w.Write([]byte("alles gut"))
}
通过 main.go 我们启动服务,监听 :8888 端口,这样我们就有了一个简单的终端 /。
golang.org/x/time/rate
我们将使用名为 x/time/rate 的 Go 包,它提供了一个令牌桶速率限制器算法。rate#Limiter 控制允许事件发生的频率。它实现了一个大小为 b 的「令牌桶」,最初是满的,并以每秒 r 的速度重新填充令牌。通俗地讲,就是在任何足够大的时间间隔内,限制器将速率限制为每秒 r 个令牌,最大突发大小为 b 个事件。
由于我们希望实现每个 IP 地址的速率限制器,我们还需要维护一个限制器映射。
package main
import (
"sync"
"golang.org/x/time/rate"
)
// IPRateLimiter .
type IPRateLimiter struct {
ips map[string]*rate.Limiter
mu *sync.RWMutex
r rate.Limit
b int
}
// NewIPRateLimiter .
func NewIPRateLimiter(r rate.Limit, b int) *IPRateLimiter {
i := &IPRateLimiter{
ips: make(map[string]*rate.Limiter),
mu: &sync.RWMutex{},
r: r,
b: b,
}
return i
}
// AddIP 创建了一个新的速率限制器,并将其添加到 ips 映射中,
// 使用 IP地址作为密钥
func (i *IPRateLimiter) AddIP(ip string) *rate.Limiter {
i.mu.Lock()
defer i.mu.Unlock()
limiter := rate.NewLimiter(i.r, i.b)
i.ips[ip] = limiter
return limiter
}
// GetLimiter 返回所提供的IP地址的速率限制器(如果存在的话).
// 否则调用 AddIP 将 IP 地址添加到映射中
func (i *IPRateLimiter) GetLimiter(ip string) *rate.Limiter {
i.mu.Lock()
limiter, exists := i.ips[ip]
if !exists {
i.mu.Unlock()
return i.AddIP(ip)
}
i.mu.Unlock()
return limiter
}
NewIPRateLimiter 创建一个 IP 限制器实例,HTTP 服务器必须调用这个实例的 GetLimiter 来获得指定 IP 的限制器 (从映射或生成一个新的)。
中间件
让我们升级的 HTTP 服务并将中间件添加到所有端点,如果 IP 达到限制,它将响应 429 Too Many Requests,否则,它将继续该请求。
每一个经过中间件的请求,我们都会调用 limitMiddleware 函数中的全局方法 Allow()。如果存储桶中没有令牌了,该方法会返回 false,该请求会收到 429 Too Many Requests 的响应。否则 Allow() 方法将消耗一个令牌,并将请求传递给下一个程序。
package main
import (
"log"
"net/http"
)
var limiter = NewIPRateLimiter(1, 5)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", okHandler)
if err := http.ListenAndServe(":8888", limitMiddleware(mux)); err != nil {
log.Fatalf("unable to start server: %s", err.Error())
}
}
func limitMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
limiter := limiter.GetLimiter(r.RemoteAddr)
if !limiter.Allow() {
http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
return
}
next.ServeHTTP(w, r)
})
}
func okHandler(w http.ResponseWriter, r *http.Request) {
// 非常重要的数据请求(译者注:这句话没理解到位)
w.Write([]byte("alles gut"))
}
编译 & 执行
go get golang.org/x/time/rate go build -o server . ./server
测试
这是我喜欢使用的一个非常好的来进行 HTTP 负载测试的工具,它叫做 vegeta (它也是用 Go 编写的)。
brew install vegeta
我们需要创建一个简单的配置文件,来展示我们希望生成的请求。
GET http://localhost:8888/
然后运行攻击 10 秒,每个时间单位 100 个请求。
vegeta attack -duration=10s -rate=100 -targets=vegeta.conf | vegeta report
结果,您将看到一些请求返回了 200,但是大多数都返回了 429。
以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于Golang的相关知识,也可关注golang学习网公众号。
golang实现redis的延时消息队列功能示例
- 上一篇
- golang实现redis的延时消息队列功能示例
- 下一篇
- Go中recover与panic区别详解
-
- Golang · Go教程 | 44分钟前 |
- Go 解析函数边界用例漏测:用 fuzz seed 和回归语料固定崩溃输入
- 168浏览 收藏
-
- Golang · Go教程 | 55分钟前 | 并发 · go · 排障 · channel context pprof goroutine 泄漏
- Go channel 消费者无法退出:用 Context 和 goroutine profile 找出泄漏点
- 171浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go 数据竞争只在压测出现:把 -race 接入高覆盖测试并读懂报告
- 239浏览 收藏
-
- Golang · Go教程 | 2小时前 | go · 数据库 · Context · 超时控制 · 连接池 · Go context database/sql 数据库超时 QueryContext
- Go 数据库请求超时后仍占连接:正确传递 Context 并确认取消生效
- 437浏览 收藏
-
- Golang · Go教程 | 2小时前 | 依赖管理 · go · 多模块 · 故障排查 · Go Modules · Go模块 gowork go.work go work use 多模块工作区
- go.work 本地联调版本不生效:定位 GOWORK、use 与模块选择结果
- 336浏览 收藏
-
- Golang · Go教程 | 11小时前 | go · testing · CI · Go 1.26 testing.ArtifactDir 测试产物
- Go 1.26 testing.ArtifactDir 怎么留测试产物:-artifacts 与临时目录取舍
- 497浏览 收藏
-
- Golang · Go教程 | 11小时前 | Go教程 · 性能排查 · 运行时指标 · Go GOMAXPROCS runnable Go 1.26 runtime/metrics waiting
- Go 1.26 runtime/metrics 调度指标怎么选:runnable、waiting 与线程数的诊断边界
- 405浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- SuperCLUE
- SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
- 127次使用
-
- C-Eval
- 深入了解C-Eval中文评估套件,涵盖52个学科与4级难度。本文详解其功能特点、Zero-shot/Few-shot使用方法及代码示例,助您全面评测LLM中文理解与泛化能力。
- 46次使用
-
- Google AI提示词库
- 探索Google Cloud官方生成式AI提示词库,提供免费、无需登录的中英双语Prompt模板。涵盖内容创作、代码优化、数据分析等场景,助您快速提升AI交互效率与质量。
- 19次使用
-
- Gradio
- Gradio是一个用于构建机器学习和数据科学Web应用的开源Python库。支持快速创建交互界面,获Google、Meta等大厂青睐,适合模型演示、部署反馈及调试。
- 128次使用
-
- AgentGPT
- 深入了解AgentGPT:一款基于浏览器的自主人工智能代理工具。本文解析其核心功能、技术栈、应用场景,并提供详细的在线使用及本地部署教程,助您高效利用AI自动化完成任务。
- 20次使用
-
- Golang实现HTTP编程请求和响应
- 2022-12-28 101浏览
-
- golangNewRequest/gorequest实现http请求的示例代码
- 2023-01-24 343浏览
-
- 一文详解Golang中net/http包的实现原理
- 2022-12-29 419浏览
-
- 快速掌握Go语言HTTP标准库的实现方法
- 2022-12-30 327浏览
-
- Go http请求排队处理实战示例
- 2022-12-23 265浏览

