optimized_go_tools/am_ratelimit/ratelimit.go
2024-07-08 11:14:19 +08:00

74 lines
2.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()
}