限流改为全局应用
This commit is contained in:
@@ -596,9 +596,9 @@ func formatPlatformText(platform string) string {
|
||||
func initImageTarRoutes(router *gin.Engine) {
|
||||
imageAPI := router.Group("/api/image")
|
||||
{
|
||||
imageAPI.GET("/download/:image", RateLimitMiddleware(globalLimiter), handleDirectImageDownload)
|
||||
imageAPI.GET("/info/:image", RateLimitMiddleware(globalLimiter), handleImageInfo)
|
||||
imageAPI.POST("/batch", RateLimitMiddleware(globalLimiter), handleSimpleBatchDownload)
|
||||
imageAPI.GET("/download/:image", handleDirectImageDownload)
|
||||
imageAPI.GET("/info/:image", handleImageInfo)
|
||||
imageAPI.POST("/batch", handleSimpleBatchDownload)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
11
src/main.go
11
src/main.go
@@ -84,6 +84,9 @@ func main() {
|
||||
})
|
||||
}))
|
||||
|
||||
// 全局限流中间件 - 应用到所有路由
|
||||
router.Use(RateLimitMiddleware(globalLimiter))
|
||||
|
||||
// 初始化监控端点
|
||||
initHealthRoutes(router)
|
||||
|
||||
@@ -113,15 +116,15 @@ func main() {
|
||||
RegisterSearchRoute(router)
|
||||
|
||||
// 注册Docker认证路由(/token*)
|
||||
router.Any("/token", RateLimitMiddleware(globalLimiter), ProxyDockerAuthGin)
|
||||
router.Any("/token/*path", RateLimitMiddleware(globalLimiter), ProxyDockerAuthGin)
|
||||
router.Any("/token", ProxyDockerAuthGin)
|
||||
router.Any("/token/*path", ProxyDockerAuthGin)
|
||||
|
||||
// 注册Docker Registry代理路由
|
||||
router.Any("/v2/*path", RateLimitMiddleware(globalLimiter), ProxyDockerRegistryGin)
|
||||
router.Any("/v2/*path", ProxyDockerRegistryGin)
|
||||
|
||||
|
||||
// 注册NoRoute处理器
|
||||
router.NoRoute(RateLimitMiddleware(globalLimiter), handler)
|
||||
router.NoRoute(handler)
|
||||
|
||||
cfg := GetConfig()
|
||||
fmt.Printf("🚀 HubProxy 启动成功\n")
|
||||
|
||||
@@ -230,6 +230,14 @@ func (i *IPRateLimiter) GetLimiter(ip string) (*rate.Limiter, bool) {
|
||||
// RateLimitMiddleware 速率限制中间件
|
||||
func RateLimitMiddleware(limiter *IPRateLimiter) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 静态文件豁免:跳过限流检查
|
||||
path := c.Request.URL.Path
|
||||
if path == "/" || path == "/favicon.ico" || path == "/images.html" || path == "/search.html" ||
|
||||
strings.HasPrefix(path, "/public/") {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
// 获取客户端真实IP
|
||||
var ip string
|
||||
|
||||
@@ -295,25 +303,4 @@ func RateLimitMiddleware(limiter *IPRateLimiter) gin.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyRateLimit 应用限流到特定路由
|
||||
func ApplyRateLimit(router *gin.Engine, path string, method string, handler gin.HandlerFunc) {
|
||||
// 使用全局限流器
|
||||
limiter := globalLimiter
|
||||
if limiter == nil {
|
||||
limiter = initGlobalLimiter()
|
||||
}
|
||||
|
||||
// 根据HTTP方法应用限流
|
||||
switch method {
|
||||
case "GET":
|
||||
router.GET(path, RateLimitMiddleware(limiter), handler)
|
||||
case "POST":
|
||||
router.POST(path, RateLimitMiddleware(limiter), handler)
|
||||
case "PUT":
|
||||
router.PUT(path, RateLimitMiddleware(limiter), handler)
|
||||
case "DELETE":
|
||||
router.DELETE(path, RateLimitMiddleware(limiter), handler)
|
||||
default:
|
||||
router.Any(path, RateLimitMiddleware(limiter), handler)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,14 +71,6 @@ func buildManifestCacheKey(imageRef, reference string) string {
|
||||
return buildCacheKey("manifest", key)
|
||||
}
|
||||
|
||||
func buildManifestCacheKeyWithPlatform(imageRef, reference, platform string) string {
|
||||
if platform == "" {
|
||||
platform = "default"
|
||||
}
|
||||
key := fmt.Sprintf("%s:%s@%s", imageRef, reference, platform)
|
||||
return buildCacheKey("manifest", key)
|
||||
}
|
||||
|
||||
func getManifestTTL(reference string) time.Duration {
|
||||
cfg := GetConfig()
|
||||
defaultTTL := 30 * time.Minute
|
||||
@@ -149,4 +141,28 @@ func isCacheEnabled() bool {
|
||||
// isTokenCacheEnabled 检查token缓存是否启用(向后兼容)
|
||||
func isTokenCacheEnabled() bool {
|
||||
return isCacheEnabled()
|
||||
}
|
||||
|
||||
// 定期清理过期缓存,防止内存泄漏
|
||||
func init() {
|
||||
go func() {
|
||||
ticker := time.NewTicker(20 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
|
||||
for range ticker.C {
|
||||
now := time.Now()
|
||||
expiredKeys := make([]string, 0)
|
||||
|
||||
globalCache.cache.Range(func(key, value interface{}) bool {
|
||||
if cached := value.(*CachedItem); now.After(cached.ExpiresAt) {
|
||||
expiredKeys = append(expiredKeys, key.(string))
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
for _, key := range expiredKeys {
|
||||
globalCache.cache.Delete(key)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
Reference in New Issue
Block a user