限流中间件必须通过r.Use()或group.Use()注册,不可嵌入单个handler;Redis key需加业务前缀防冲突;令牌桶应优先用Redis原子操作实现;limit-count-ip与limit-time-ip须配对为正整数且中间件已挂载才生效。

限流中间件必须注册在路由组或全局,不能只挂单个 handler
很多人把限流中间件像 c.Next() 那样只写在某个 GET 或 POST 的 handler 里,结果完全不生效。Gin 的中间件必须通过 r.Use() 或 group.Use() 注册,才会在请求进入时触发。
常见错误写法:
r.GET("/api/data", func(c *gin.Context) {
// ❌ 这里写限流逻辑(比如检查 Redis 计数)是无效的
if !isAllowed(c.ClientIP()) {
c.AbortWithStatusJSON(429, gin.H{"error": "too many requests"})
return
}
c.Next()
})
正确做法是封装成标准中间件函数,再用 Use 挂载:
- 限流逻辑必须在
c.Next()前执行,否则无法拦截后续流程 - 若只对某类路由限流(如所有
/api/开头的),应创建子路由组并单独挂载:api := r.Group("/api"); api.Use(rateLimitMiddleware()) - 注意中间件执行顺序:多个
Use()按调用顺序从左到右执行,限流建议放在鉴权之后、业务处理之前
Redis 限流 key 必须带业务前缀,避免不同服务冲突
直接用 c.ClientIP() 作为 Redis key(如 "ip:" + c.ClientIP())在多服务共用一个 Redis DB 时极易撞 key。比如用户服务和订单服务都用 "ip:192.168.1.100",互相干扰。
推荐构造方式:
- 按接口维度:
"rate:api:/user/profile:" + c.ClientIP() - 按路由组维度:
"rate:group:admin:" + c.ClientIP() - 加版本或环境标识:
"rate:v1:prod:ip:" + c.ClientIP()
gin-vue-admin 的 limit_ip.go 就用了类似 "limit:ip:" + ip 的结构,但没加业务上下文——上线前务必补上前缀,否则压测时会发现限流阈值莫名其妙被其他模块耗尽。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
令牌桶填充逻辑必须考虑时间漂移,别只靠 time.Now()
手动实现令牌桶时,如果每次只用 now.Sub(tb.lastToken) 算间隔,遇到系统时间回拨(如 NTP 校准)、容器重启、或跨节点部署,lastToken 可能比当前时间还大,导致 tokens 突然归零或负增长。
安全做法:
- 用单调时钟(
time.Since(tb.lastToken)更稳妥,但 Go 的time.Since底层仍依赖 wall clock) - 更可靠的是改用 Redis 的
INCR+EXPIRE原子组合,像SetLimitWithTime那样,完全交由 Redis 控制窗口边界 - 若坚持内存令牌桶,至少加一层校验:
if now.Before(tb.lastToken) { tb.lastToken = now }
这也是为什么生产环境强烈建议用 Redis 而非内存实现——它天然规避了本地时钟不可靠问题。
配置项 limit-count-ip 和 limit-time-ip 不是全局开关,要配对生效
在 gin-vue-admin 的 config.yaml 中,limit-count-ip: 100 和 limit-time-ip: 60 是一组参数,单独改一个没用。它们共同决定“每 60 秒最多 100 次请求”这个窗口规则。
容易踩的坑:
- 误以为
limit-time-ip: 300表示“5 分钟内累计不超过”,其实它是滑动窗口?错,gin-vue-admin 当前用的是固定窗口计数器,不是滑动窗口 - 把
limit-count-ip设为 0 或负数,会导致SetLimitWithTime函数直接跳过判断,相当于关闭限流 - 修改配置后没重启服务或没热重载(该框架不支持限流配置热更新),改了等于白改
真正起作用的是 global.GVA_REDIS 实例是否初始化成功 + 这两个值是否为正整数 + 中间件是否被挂载。三者缺一不可。


















