60 lines
1.3 KiB
Go
60 lines
1.3 KiB
Go
package middleware
|
||
|
||
import (
|
||
"fmt"
|
||
"nl-video-api/utility/response"
|
||
"time"
|
||
|
||
"github.com/gogf/gf/v2/database/gredis"
|
||
"github.com/gogf/gf/v2/frame/g"
|
||
"github.com/gogf/gf/v2/net/ghttp"
|
||
)
|
||
|
||
// RateLimit 限流中间件
|
||
func RateLimit(maxRequests int, window time.Duration) func(r *ghttp.Request) {
|
||
return func(r *ghttp.Request) {
|
||
var (
|
||
ctx = r.Context()
|
||
client = g.Redis()
|
||
key = fmt.Sprintf("rate_limit:%s", r.GetClientIp())
|
||
)
|
||
|
||
// 获取当前请求次数
|
||
count, err := client.Get(ctx, key)
|
||
if err != nil {
|
||
g.Log().Error(ctx, "Redis获取失败:", err)
|
||
r.Middleware.Next()
|
||
return
|
||
}
|
||
|
||
// 检查是否超过限制
|
||
if count.Int() >= maxRequests {
|
||
response.Error(r, response.CodeError, "请求过于频繁,请稍后再试")
|
||
return
|
||
}
|
||
|
||
// 增加计数
|
||
if count.Int() == 0 {
|
||
// 第一次请求,设置过期时间
|
||
seconds := int64(window.Seconds())
|
||
client.Set(ctx, key, 1, gredis.SetOption{
|
||
TTLOption: gredis.TTLOption{EX: &seconds},
|
||
})
|
||
} else {
|
||
// 增加计数
|
||
client.Incr(ctx, key)
|
||
}
|
||
|
||
r.Middleware.Next()
|
||
}
|
||
}
|
||
|
||
// APIRateLimit API接口限流(每分钟60次)
|
||
func APIRateLimit(r *ghttp.Request) {
|
||
RateLimit(60, time.Minute)(r)
|
||
}
|
||
|
||
// LoginRateLimit 登录接口限流(每分钟5次)
|
||
func LoginRateLimit(r *ghttp.Request) {
|
||
RateLimit(5, time.Minute)(r)
|
||
} |