From 4c6751b86214b4d9fe86bf721c1c29e54e84fb7e Mon Sep 17 00:00:00 2001 From: user123456 Date: Wed, 18 Jun 2025 19:44:32 +0800 Subject: [PATCH] =?UTF-8?q?=E9=99=90=E6=B5=81=E6=94=B9=E4=B8=BA=E5=85=A8?= =?UTF-8?q?=E5=B1=80=E5=BA=94=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/imagetar.go | 6 +++--- src/main.go | 11 +++++++---- src/ratelimiter.go | 31 +++++++++---------------------- src/token_cache.go | 32 ++++++++++++++++++++++++-------- 4 files changed, 43 insertions(+), 37 deletions(-) diff --git a/src/imagetar.go b/src/imagetar.go index 788080e..6dfc585 100644 --- a/src/imagetar.go +++ b/src/imagetar.go @@ -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) } } diff --git a/src/main.go b/src/main.go index 036ea9e..f4a43a4 100644 --- a/src/main.go +++ b/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") diff --git a/src/ratelimiter.go b/src/ratelimiter.go index 3d302ec..249992e 100644 --- a/src/ratelimiter.go +++ b/src/ratelimiter.go @@ -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) - } -} + diff --git a/src/token_cache.go b/src/token_cache.go index 65edf45..77a56c7 100644 --- a/src/token_cache.go +++ b/src/token_cache.go @@ -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) + } + } + }() } \ No newline at end of file