Skip to content

接口限流

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  # 窗口重置时间

基于 MIT 许可发布