From 0bcb1fec876da1abc6ad90aa5149530047a30a8c Mon Sep 17 00:00:00 2001 From: truewhile <62226914+truewhile@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:21:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BD=91=E7=9B=98=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E8=AF=BB=E5=8F=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化网盘图片读取逻辑 --- internal/service/image_proxy.go | 1 - internal/service/image_proxy_cache.go | 9 ++------- internal/service/image_proxy_remote.go | 22 ++++----------------- internal/service/image_proxy_remote_test.go | 7 ++++--- 4 files changed, 10 insertions(+), 29 deletions(-) diff --git a/internal/service/image_proxy.go b/internal/service/image_proxy.go index e0f9080..b73772e 100644 --- a/internal/service/image_proxy.go +++ b/internal/service/image_proxy.go @@ -44,7 +44,6 @@ type ImageProxy struct { const ( imageBrowserCacheControl = "public, max-age=2592000, immutable" imagePlaceholderCacheControl = "no-store" - imageNegativeCacheTTL = 6 * time.Hour ) // NewImageProxy is the constructor. diff --git a/internal/service/image_proxy_cache.go b/internal/service/image_proxy_cache.go index 691d826..4e5a639 100644 --- a/internal/service/image_proxy_cache.go +++ b/internal/service/image_proxy_cache.go @@ -132,14 +132,9 @@ func imageFileETag(key string, stat os.FileInfo) string { } func freshNegativeImageCache(failPath string) bool { - stat, err := os.Stat(failPath) - if err != nil { - return false + if _, err := os.Stat(failPath); err == nil { + _ = os.Remove(failPath) } - if time.Since(stat.ModTime()) < imageNegativeCacheTTL { - return true - } - _ = os.Remove(failPath) return false } diff --git a/internal/service/image_proxy_remote.go b/internal/service/image_proxy_remote.go index 40d59a5..2096337 100644 --- a/internal/service/image_proxy_remote.go +++ b/internal/service/image_proxy_remote.go @@ -86,9 +86,8 @@ func (p *ImageProxy) serveRemoteImage(ctx context.Context, w http.ResponseWriter if !forceRefresh && serveCachedImageFile(w, r, key, cachePath) { return nil } - if !forceRefresh && p.serveFreshRemoteFailure(w, failPath) { - return nil - } + // No negative caching: a previously failed fetch is retried on every + // subsequent request, so the image recovers as soon as upstream does. data, ctype, contentLength, err := p.fetchAndCacheRemoteImage(ctx, raw, host, cachePath, failPath) if err != nil { if forceRefresh && serveCachedImageFile(w, r, key, cachePath) { @@ -128,16 +127,6 @@ func (p *ImageProxy) removeUnusableImageCache(cachePath, failPath string) { _ = os.Remove(failPath) } -func (p *ImageProxy) serveFreshRemoteFailure(w http.ResponseWriter, failPath string) bool { - if stat, err := os.Stat(failPath); err == nil && time.Since(stat.ModTime()) < imageNegativeCacheTTL { - serveCachedPlaceholder(w) - return true - } else if err == nil { - _ = os.Remove(failPath) - } - return false -} - func (p *ImageProxy) fetchAndCacheRemoteImage(ctx context.Context, raw, host, cachePath, failPath string) ([]byte, string, string, error) { if err := os.MkdirAll(p.cacheDir, 0o750); err != nil { p.log.Warn("imageproxy: mkdir failed", zap.String("dir", p.cacheDir), zap.Error(err)) @@ -188,11 +177,8 @@ func (p *ImageProxy) Fetch(ctx context.Context, raw string) ([]byte, string, err _ = os.Remove(cachePath) _ = os.Remove(failPath) } - if stat, err := os.Stat(failPath); err == nil && time.Since(stat.ModTime()) < imageNegativeCacheTTL { - return nil, "", errors.New("recent image fetch failure") - } else if err == nil { - _ = os.Remove(failPath) - } + // No negative caching: a previously failed fetch is retried on every + // subsequent request, so the image recovers as soon as upstream does. data, ctype, _, err := p.fetchAndCacheRemoteImage(ctx, raw, host, cachePath, failPath) return data, ctype, err } diff --git a/internal/service/image_proxy_remote_test.go b/internal/service/image_proxy_remote_test.go index 2f56ef0..1d83bd6 100644 --- a/internal/service/image_proxy_remote_test.go +++ b/internal/service/image_proxy_remote_test.go @@ -17,7 +17,7 @@ import ( "github.com/ShukeBta/MediaStationGo/internal/config" ) -func TestImageProxyCachesFailedRemoteImageFetch(t *testing.T) { +func TestImageProxyDoesNotNegativeCacheFailedRemoteImageFetch(t *testing.T) { var calls int32 proxy := NewImageProxy(&config.Config{Cache: config.CacheConfig{CacheDir: filepath.Join(t.TempDir(), "cache")}}, zap.NewNop()) proxy.client = &http.Client{Transport: imageRoundTripFunc(func(req *http.Request) (*http.Response, error) { @@ -42,12 +42,13 @@ func TestImageProxyCachesFailedRemoteImageFetch(t *testing.T) { if rec.Body.Len() != len(transparent1x1PNG) { t.Fatalf("body length = %d, want placeholder %d", rec.Body.Len(), len(transparent1x1PNG)) } + // No negative caching: every request re-attempts upstream. if got := rec.Header().Get("Cache-Control"); got != imagePlaceholderCacheControl { t.Fatalf("Cache-Control = %q, want %q", got, imagePlaceholderCacheControl) } } - if got := atomic.LoadInt32(&calls); got != 1 { - t.Fatalf("upstream calls = %d, want 1 due to negative cache", got) + if got := atomic.LoadInt32(&calls); got != 2 { + t.Fatalf("upstream calls = %d, want 2 (one per request, no negative cache)", got) } }