golang实现HTTP请求速率限制的插件库Tollbooth的使用

Golang实现HTTP请求速率限制的插件库Tollbooth的使用

Tollbooth是一个通用的中间件,用于对HTTP请求进行速率限制。

版本说明

五分钟教程

package main

import (
    "net/http"
    "github.com/didip/tollbooth/v8"
    "github.com/didip/tollbooth/v8/limiter"
)

func HelloHandler(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte("Hello, World!"))
}

func main() {
    // 创建每个处理程序的请求限制器
    lmt := tollbooth.NewLimiter(1, nil)

    // 版本>=8的新功能,必须明确定义如何选择IP地址
    lmt.SetIPLookup(limiter.IPLookup{
        Name:           "X-Real-IP",
        IndexFromRight: 0,
    })

    // 版本>=8的新功能,HTTPMiddleware是与标准路由器兼容的替代方案
    http.Handle("/", tollbooth.HTTPMiddleware(lmt)(http.HandlerFunc(HelloHandler)))
    // 旧语法:
    // http.Handle("/", tollbooth.LimitFuncHandler(lmt, HelloHandler))

    http.ListenAndServe(":12345", nil)
}

主要特性

  1. 多种限制条件:可以基于远程IP、路径、方法、自定义头和基本认证用户名进行限制
import (
    "time"
    "github.com/didip/tollbooth/v8"
    "github.com/didip/tollbooth/v8/limiter"
)

lmt := tollbooth.NewLimiter(1, nil)

// 或创建带有可过期令牌桶的限制器
lmt = tollbooth.NewLimiter(1, &limiter.ExpirableOptions{DefaultExpirationTTL: time.Hour})

// 版本>=8的新功能,必须明确定义如何选择IP地址
lmt.SetIPLookup(limiter.IPLookup{
    Name:           "X-Real-IP",
    IndexFromRight: 0,
})

// 仅限制GET和POST请求
lmt.SetMethods([]string{"GET", "POST"})

// 基于基本认证用户名限制
lmt.SetBasicAuthUsers([]string{"bob", "jane", "didip", "vip"})
lmt.RemoveBasicAuthUsers([]string{"vip"})

// 限制包含特定值的请求头
lmt.SetHeader("X-Access-Token", []string{"abc123", "xyz098"})
lmt.RemoveHeader("X-Access-Token")
lmt.RemoveHeaderEntries("X-Access-Token", []string{"limitless-token"})
  1. 自定义过期时间:可以设置各种元素的过期TTL
import "time"

lmt := tollbooth.NewLimiter(1, nil)

// 设置令牌桶的自定义过期TTL
lmt.SetTokenBucketExpirationTTL(time.Hour)

// 设置基本认证用户的过期TTL
lmt.SetBasicAuthExpirationTTL(time.Hour)

// 设置头条目的过期TTL
lmt.SetHeaderEntryExpirationTTL(time.Hour)
  1. 自定义拒绝响应:可以设置自定义消息或拒绝回调函数
lmt := tollbooth.NewLimiter(1, nil)

lmt.SetIPLookup(limiter.IPLookup{
    Name:           "X-Forwarded-For",
    IndexFromRight: 0,
})

// 设置自定义消息
lmt.SetMessage("You have reached maximum request limit.")

// 设置自定义内容类型
lmt.SetMessageContentType("text/plain; charset=utf-8")

// 设置拒绝时的自定义函数
lmt.SetOnLimitReached(func(w http.ResponseWriter, r *http.Request) { 
    fmt.Println("A request was rejected") 
})
  1. 响应头信息:在被拒绝时会返回以下HTTP响应头:

    • X-Rate-Limit-Limit
    • X-Rate-Limit-Duration
    • X-Rate-Limit-Request-Forwarded-For
    • X-Rate-Limit-Request-Remote-Addr
  2. 使用Token Bucket算法:不需要外部存储

其他Web框架集成

Tollbooth可以与其他Web框架集成,社区提供了以下适配器:

  • Chi
  • Echo
  • FastHTTP
  • Gin
  • GoRestful
  • HTTPRouter
  • Iris
  • Negroni

完整示例

package main

import (
    "fmt"
    "net/http"
    "time"
    "github.com/didip/tollbooth/v8"
    "github.com/didip/tollbooth/v8/limiter"
)

func main() {
    // 创建限制器:1请求/秒,令牌桶1小时后过期
    lmt := tollbooth.NewLimiter(1, &limiter.ExpirableOptions{
        DefaultExpirationTTL: time.Hour,
    })

    // 设置IP查找方式
    lmt.SetIPLookup(limiter.IPLookup{
        Name:           "X-Forwarded-For",
        IndexFromRight: 0,
    })

    // 仅限制GET请求
    lmt.SetMethods([]string{"GET"})

    // 设置自定义拒绝消息
    lmt.SetMessage("您已达到请求速率限制,请稍后再试。")
    lmt.SetMessageContentType("text/plain; charset=utf-8")

    // 自定义拒绝处理函数
    lmt.SetOnLimitReached(func(w http.ResponseWriter, r *http.Request) {
        fmt.Printf("请求被限制: %s %s\n", r.Method, r.URL.Path)
    })

    // 创建处理函数
    helloHandler := func(w http.ResponseWriter, req *http.Request) {
        w.Write([]byte("Hello, World!"))
    }

    // 应用速率限制中间件
    http.Handle("/", tollbooth.HTTPMiddleware(lmt)(http.HandlerFunc(helloHandler)))

    fmt.Println("服务器启动在 :8080")
    http.ListenAndServe(":8080", nil)
}

这个示例展示了Tollbooth的主要功能,包括速率限制设置、IP查找配置、方法限制、自定义消息和拒绝回调等。


更多关于golang实现HTTP请求速率限制的插件库Tollbooth的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现HTTP请求速率限制的插件库Tollbooth的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Tollbooth:Golang HTTP请求速率限制库

Tollbooth 是一个简单高效的 Golang HTTP 请求速率限制中间件,可以帮助你轻松地为 Web 服务添加请求限制功能。

主要特性

  • 支持基于 IP、请求头或自定义键的速率限制
  • 支持内存和 Redis 存储
  • 简单易用的 API
  • 轻量级,无额外依赖

安装

go get github.com/didip/tollbooth/v7

基本使用

1. 简单速率限制

package main

import (
	"net/http"
	"time"
	
	"github.com/didip/tollbooth/v7"
	"github.com/didip/tollbooth/v7/limiter"
)

func main() {
	// 创建一个限制器:每秒最多1个请求
	lmt := tollbooth.NewLimiter(1, &limiter.ExpirableOptions{
		DefaultExpirationTTL: time.Hour,
	})
	
	// 设置超出限制时的处理函数
	lmt.SetOnLimitReached(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusTooManyRequests)
		w.Write([]byte("Too many requests"))
	})
	
	// 应用限制器到处理器
	http.Handle("/", tollbooth.LimitFuncHandler(lmt, func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, World!"))
	}))
	
	http.ListenAndServe(":8080", nil)
}

2. 基于IP的限制

package main

import (
	"net/http"
	"time"
	
	"github.com/didip/tollbooth/v7"
	"github.com/didip/tollbooth/v7/limiter"
)

func main() {
	lmt := tollbooth.NewLimiter(1, &limiter.ExpirableOptions{
		DefaultExpirationTTL: time.Hour,
	})
	
	// 基于客户端IP进行限制
	lmt.SetIPLookups([]string{"RemoteAddr", "X-Forwarded-For", "X-Real-IP"})
	
	http.Handle("/", tollbooth.LimitFuncHandler(lmt, func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, World!"))
	}))
	
	http.ListenAndServe(":8080", nil)
}

3. 与标准库集成

package main

import (
	"net/http"
	"time"
	
	"github.com/didip/tollbooth/v7"
	"github.com/didip/tollbooth/v7/limiter"
)

func main() {
	lmt := tollbooth.NewLimiter(1, &limiter.ExpirableOptions{
		DefaultExpirationTTL: time.Hour,
	})
	
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, World!"))
	})
	
	// 包装整个路由器
	http.ListenAndServe(":8080", tollbooth.LimitHandler(lmt, mux))
}

4. 与Gin框架集成

package main

import (
	"github.com/didip/tollbooth/v7"
	"github.com/didip/tollbooth/v7/limiter"
	"github.com/gin-gonic/gin"
	"time"
)

func main() {
	r := gin.Default()
	
	lmt := tollbooth.NewLimiter(1, &limiter.ExpirableOptions{
		DefaultExpirationTTL: time.Hour,
	})
	
	r.GET("/", func(c *gin.Context) {
		// 在处理器内部检查限制
		httpError := tollbooth.LimitByRequest(lmt, c.Writer, c.Request)
		if httpError != nil {
			c.Data(httpError.StatusCode, "text/plain", []byte(httpError.Message))
			c.Abort()
			return
		}
		
		c.String(200, "Hello, World!")
	})
	
	r.Run(":8080")
}

高级配置

1. 使用Redis作为存储后端

package main

import (
	"net/http"
	"time"
	
	"github.com/didip/tollbooth/v7"
	"github.com/didip/tollbooth/v7/limiter"
	"github.com/go-redis/redis/v8"
)

func main() {
	// 创建Redis客户端
	rdb := redis.NewClient(&redis.Options{
		Addr: "localhost:6379",
	})
	
	// 创建基于Redis的限制器
	lmt := tollbooth.NewLimiter(1, &limiter.ExpirableOptions{
		DefaultExpirationTTL: time.Hour,
	})
	
	// 设置Redis存储
	lmt.SetStore(limiter.NewRedisStore(rdb))
	
	http.Handle("/", tollbooth.LimitFuncHandler(lmt, func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, World!"))
	}))
	
	http.ListenAndServe(":8080", nil)
}

2. 自定义限制键

package main

import (
	"net/http"
	"time"
	
	"github.com/didip/tollbooth/v7"
	"github.com/didip/tollbooth/v7/limiter"
)

func main() {
	lmt := tollbooth.NewLimiter(1, &limiter.ExpirableOptions{
		DefaultExpirationTTL: time.Hour,
	})
	
	// 自定义限制键生成函数
	lmt.SetBasicAuthUsers([]string{"user1", "user2"})
	lmt.SetHeader("X-API-Key", []string{"key1", "key2"})
	
	http.Handle("/", tollbooth.LimitFuncHandler(lmt, func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, World!"))
	}))
	
	http.ListenAndServe(":8080", nil)
}

最佳实践

  1. 合理设置限制:根据API的实际负载能力设置限制值
  2. 区分端点:可以为不同的API端点设置不同的限制
  3. 监控和调整:定期监控限制情况并根据实际使用情况调整限制值
  4. 考虑使用Redis:在分布式环境中,使用Redis作为存储后端可以保持限制的一致性

Tollbooth是一个简单而强大的库,可以轻松地为你的Golang Web服务添加速率限制功能,保护你的服务免受滥用和DDoS攻击。

回到顶部