middleware/rateLimiterMiddleware.go
package middleware
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"golang.org/x/time/rate"
)
var Limiter *rate.Limiter
// 定义一个中间件函数来进行限流
func RateLimiterMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
if !Limiter.AllowN(time.Now(), 1) {
c.JSON(http.StatusTooManyRequests, gin.H{"message": "Rate limit exceeded"})
// 设置休眠和业务时长一样,为了更好从日志出看出规则
time.Sleep(50 * time.Millisecond)
c.Abort()
return
}
c.Next()
}
}
main.go
func main() {
r := gin.Default()
// 创建一个限流器,每秒允许最多10个请求
middleware.Limiter = rate.NewLimiter(rate.Limit(10), 1)
// 使用限流中间件
r.Use(middleware.RateLimiterMiddleware())
r.GET("/api/resource", func(c *gin.Context) {
time.Sleep(50 * time.Millisecond)
c.JSON(http.StatusOK, gin.H{"message": "Resource accessed"})
})
r.Run(":8080")
}
使用ab压力测试,并发量为1的(相当于串行),在1秒内不断发出请求(算下来,每个请求50ms,总共能发出20个请求)
middleware/ipRateLimiterMiddleware.go
package middleware
import (
"net/http"
"sync"
"time"
"github.com/gin-gonic/gin"
"golang.org/x/time/rate"
)
var IPLimiter *IPRateLimiter
func NewIPRateLimiter() *IPRateLimiter {
return &IPRateLimiter{
limiter: make(map[string]*rate.Limiter),
}
}
type IPRateLimiter struct {
mu sync.Mutex
limiter map[string]*rate.Limiter
}
func (i *IPRateLimiter) GetLimiter(ip string) *rate.Limiter {
i.mu.Lock()
defer i.mu.Unlock()
limiter, exists := i.limiter[ip]
if !exists {
limiter = rate.NewLimiter(2, 5) // 每秒2个请求,桶容量为5
i.limiter[ip] = limiter
}
return limiter
}
// 定义一个中间件函数来进行限流
func IPRateLimiterMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
ip := c.ClientIP()
limiter := IPLimiter.GetLimiter(ip)
if !limiter.Allow() {
c.JSON(http.StatusTooManyRequests, gin.H{"message": "Rate limit exceeded"})
// 设置休眠和业务时长一样,为了更好从日志出看出规则
time.Sleep(50 * time.Millisecond)
c.Abort()
return
}
c.Next()
}
}
main.go
func main() {
r := gin.Default()
// 创建IP限流器
middleware.IPLimiter = middleware.NewIPRateLimiter()
// 使用限流中间件
r.Use(middleware.IPRateLimiterMiddleware())
r.GET("/api/resource", func(c *gin.Context) {
time.Sleep(50 * time.Millisecond)
c.JSON(http.StatusOK, gin.H{"message": "Resource accessed"})
})
r.Run(":8080")
}
使用ab压力测试,并发量为1的(相当于串行),在1秒内不断发出请求(算下来,每个请求50ms,总共能发出20个请求)