feat(middleware): 添加请求绑定与限流中间件

This commit is contained in:
unclesam committed 2026-07-07 21:23:40 +08:00
1 parent 329a22f0b1
commit 4cec3f131a
9 files changed
+2017

No files matched your search

+44
View File
@@ -0,0 +1,44 @@
package middleware
import (
"EnGin/internal/utils/res"
"github.com/gin-gonic/gin"
)
func BindJsonMiddleware[T any](c *gin.Context) {
var cr T
err := c.ShouldBindJSON(&cr)
if err != nil {
res.FailWithError(err, c)
c.Abort()
return
}
c.Set("request", cr)
}
func BindQueryMiddleware[T any](c *gin.Context) {
var cr T
err := c.ShouldBindQuery(&cr)
if err != nil {
res.FailWithError(err, c)
c.Abort()
return
}
c.Set("request", cr)
}
func BindUriMiddleware[T any](c *gin.Context) {
var cr T
err := c.ShouldBindUri(&cr)
if err != nil {
res.FailWithError(err, c)
c.Abort()
return
}
c.Set("request", cr)
}
func GetBind[T any](c *gin.Context) (cr T) {
return c.MustGet("request").(T)
}
+98
View File
@@ -0,0 +1,98 @@
package middleware
import (
"EnGin/internal/db"
"EnGin/internal/utils/res"
"context"
"fmt"
"time"
"github.com/gin-gonic/gin"
)
// LimitConfig 限流配置
type LimitConfig struct {
MaxRequest int // 最大请求数
TimeWindow time.Duration // 时间窗口
Message string // 提示信息
}
var (
DefaultLimit = LimitConfig{
MaxRequest: 100,
TimeWindow: 60 * time.Second,
Message: "请求过于频繁,请稍后重试",
}
SearchLimit = LimitConfig{
MaxRequest: 20,
TimeWindow: 60 * time.Second,
Message: "搜索过于频繁,请稍后重试",
}
AuthLimit = LimitConfig{
MaxRequest: 5,
TimeWindow: 60 * time.Second,
Message: "登录尝试过多,请稍后重试",
}
PaymentLimit = LimitConfig{
MaxRequest: 3,
TimeWindow: 60 * time.Second,
Message: "操作过于频繁,请稍后重试",
}
)
// RateLimitMiddleware ip限流器
func RateLimitMiddleware(c *gin.Context, config LimitConfig) {
ip := c.ClientIP()
key := fmt.Sprintf("rate_limit:%s", ip)
ctx := context.Background()
// 获取当前计数
count, err := db.Redis.Get(ctx, key).Int()
if err != nil && err.Error() != "redis: nil" {
// Redis 错误,放行请求(降级策略)
c.Next()
return
}
// 检查是否超限
if count >= config.MaxRequest {
res.FailWithMsg("请求过于频繁,请稍后重试", c)
c.Abort()
return
}
// 增加计数
pipe := db.Redis.Pipeline()
pipe.Incr(ctx, key)
pipe.Expire(ctx, key, config.TimeWindow)
_, err = pipe.Exec(ctx)
if err != nil {
// Redis 错误,放行请求
c.Next()
return
}
c.Next()
}
// 快捷方法
func DefaultRateLimit(c *gin.Context) {
RateLimitMiddleware(c, DefaultLimit)
}
func SearchRateLimit(c *gin.Context) {
RateLimitMiddleware(c, SearchLimit)
}
func AuthRateLimit(c *gin.Context) {
RateLimitMiddleware(c, AuthLimit)
}
func PaymentRateLimit(c *gin.Context) {
RateLimitMiddleware(c, AuthLimit)
}