接口限流
youlai-gin 基于 gin-limiter 实现接口限流,防止恶意请求和系统过载。
限流配置
yaml
# configs/dev.yaml
rateLimit:
enabled: true
type: redis # memory / redis
redis:
key: "rate_limit:%s"
default:
requests: 100 # 请求数
duration: 1m # 时间窗口使用方式
1. 全局限流
go
// main.go
import "youlai-gin/pkg/middleware"
func main() {
r := gin.New()
// 全局限流:100次/分钟
r.Use(middleware.RateLimit(100, time.Minute))
r.Run(":8080")
}2. 路由级限流
go
// 登录接口限流:5次/分钟
authGroup := r.Group("/api/auth")
authGroup.Use(middleware.RateLimit(5, time.Minute))
{
authGroup.POST("/login", authHandler.Login)
}3. 基于 IP 限流
go
import "github.com/ulule/limiter/v3"
import "github.com/ulule/limiter/v3/drivers/store/redis"
func IPRateLimit() gin.HandlerFunc {
store, _ := redis.NewStoreWithOptions(redisClient, limiter.StoreOptions{
Prefix: "rate_limit",
})
rate := limiter.Rate{
Period: time.Minute,
Limit: 100,
}
instance := limiter.New(store, rate)
return func(c *gin.Context) {
key := c.ClientIP()
context, err := instance.Get(c, key)
if err != nil {
c.AbortWithStatus(500)
return
}
c.Header("X-RateLimit-Limit", strconv.FormatInt(context.Limit, 10))
c.Header("X-RateLimit-Remaining", strconv.FormatInt(context.Remaining, 10))
if context.Reached {
c.JSON(429, gin.H{"code": 429, "msg": "请求过于频繁"})
c.Abort()
return
}
c.Next()
}
}限流策略
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 固定窗口 | 固定时间窗口计数 | 简单限流 |
| 滑动窗口 | 平滑限流 | 精确限流 |
| 令牌桶 | 允许突发流量 | API 限流 |
| 漏桶 | 恒定速率 | 流量整形 |
响应头
X-RateLimit-Limit: 100 # 窗口内最大请求数
X-RateLimit-Remaining: 95 # 剩余请求数
X-RateLimit-Reset: 1640000000 # 窗口重置时间