低空智控平台 后端go
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

47 lines
1.2 KiB

package middleware
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"laic-backend/common"
"laic-backend/logger"
)
// rateLimitLua 固定窗口计数:首次计数设置过期时间,返回当前窗口计数
const rateLimitLua = `
local key = KEYS[1]
local ttl = tonumber(ARGV[1])
local n = redis.call('INCR', key)
if n == 1 then
redis.call('EXPIRE', key, ttl)
end
return n
`
// RateLimitMiddleware 基于 Redis 固定窗口的按 IP 限流(默认 300 次/分钟)
func RateLimitMiddleware(limit int64, windowSeconds int64) gin.HandlerFunc {
if limit <= 0 {
limit = 300
}
if windowSeconds <= 0 {
windowSeconds = 60
}
return func(c *gin.Context) {
key := fmt.Sprintf("laic:ratelimit:%s", c.ClientIP())
n, err := common.GetLuaInt64(rateLimitLua, []string{key}, windowSeconds)
if err != nil {
// 限流依赖 Redis,异常时放行(避免 Redis 故障拖垮全站)
logger.ERROR("限流计数失败", err)
c.Next()
return
}
if n > limit {
common.FailWithBusiErrorWithHttpStatus(c, http.StatusTooManyRequests, common.NewBusiError(http.StatusTooManyRequests, "请求过于频繁,请稍后再试"))
return
}
c.Next()
}
}