74 lines
2.1 KiB
Go
74 lines
2.1 KiB
Go
|
package am_ratelimit
|
|||
|
|
|||
|
import (
|
|||
|
"github.com/gin-gonic/gin"
|
|||
|
"net/http"
|
|||
|
"sync"
|
|||
|
"time"
|
|||
|
)
|
|||
|
|
|||
|
// 储存用户信息,包括最后一次访问时间和访问计数
|
|||
|
type RequestInfo struct {
|
|||
|
LastAccessTime time.Time
|
|||
|
RequestCount int
|
|||
|
}
|
|||
|
|
|||
|
// 互斥锁,用于同步对共享资源(如requestInfo映射)的访问,确保在多线程环境下的数据一致性
|
|||
|
var mutex = &sync.Mutex{}
|
|||
|
|
|||
|
// 速率限制配置项结构体
|
|||
|
type RateLimitConfig struct {
|
|||
|
maxRequests int // 最大访问次数
|
|||
|
timeWindow time.Duration // 窗口时间
|
|||
|
requestInfo map[string]*RequestInfo // 用户信息
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* 初始化速率限制配置
|
|||
|
* 参数:
|
|||
|
* 1. maxRequests int:窗口时间内最大访问数量限制
|
|||
|
* 2. timeWindow int:限制的窗口时间,单位为秒
|
|||
|
*/
|
|||
|
func NewRateLimitConfig(maxRequests int, timeWindow int) *RateLimitConfig {
|
|||
|
return &RateLimitConfig{
|
|||
|
maxRequests: maxRequests,
|
|||
|
timeWindow: time.Duration(timeWindow) * time.Second,
|
|||
|
requestInfo: make(map[string]*RequestInfo),
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* 速率限制中间件
|
|||
|
*/
|
|||
|
func (r1 *RateLimitConfig) RateLimitMiddleware(c *gin.Context) {
|
|||
|
ip := c.ClientIP() // 获取用户IP
|
|||
|
mutex.Lock() // 在访问共享资源前加锁,确保只有同一线程才能访问
|
|||
|
defer mutex.Unlock() // 在数据返回前解锁
|
|||
|
|
|||
|
info, exists := r1.requestInfo[ip] // 检查requestInfo映射中是否已经存在该IP信息
|
|||
|
|
|||
|
// 如果该IP的请求信息不存在,则初始化一个新的RequestInfo实例,并将其添加到requestInfo映射中
|
|||
|
if !exists {
|
|||
|
r1.requestInfo[ip] = &RequestInfo{LastAccessTime: time.Now(), RequestCount: 1}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// 如果最后一次请求的时间已经超出了时间窗口,重置请求计数并更新最后一次访问时间
|
|||
|
if time.Since(info.LastAccessTime) > r1.timeWindow {
|
|||
|
info.RequestCount = 1
|
|||
|
info.LastAccessTime = time.Now()
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// 增加请求数并检查速率限制
|
|||
|
info.RequestCount++
|
|||
|
if info.RequestCount > r1.maxRequests {
|
|||
|
c.JSON(http.StatusTooManyRequests, gin.H{"error": "Too many requests"})
|
|||
|
c.Abort()
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// 更新最后一次访问时间
|
|||
|
info.LastAccessTime = time.Now()
|
|||
|
}
|