Görsel Önbellek Stratejisi: Cache-Control Başlıkları ve CDN Ayarları
Tarayıcılar ve içerik dağıtım ağları (CDN) bir görseli her istekte yeniden indirmez; önce önbellekte arar. Önbellekte geçerli bir kopya varsa sunucuya hiç gitmez, kullanıcıya milisaniyeler içinde teslim eder. Görsel dosyaları metin tabanlı kaynaklara kıyasla çok daha büyük olduğundan, bu davranış sayfa yükleme hızını doğrudan etkiler.
Bu davranışı yönlendiren başlık Cache-Control'dür. Sunucu her yanıtta bu başlığı HTTP response header olarak gönderir; tarayıcı da CDN düğümleri de direktife göre hareket eder. Direktifi yanlış yapılandırmak iki yönde hata üretir: çok kısa tutarsanız görsel her ziyarette yeniden indirilir, çok uzun tutarsanız güncellediğiniz görsel ziyaretçilere eskisi gibi görünmeye devam eder.
Görsel önbellekleme stratejisi bu iki uç arasında uzlaşı aramak değil, doğru teknikle her ikisini de çözmektir. URL sürümleme ile birlikte kullanılan uzun önbellek süreleri, görsel değiştiğinde URL'yi de değiştirir; eski önbellek içeriği sizi bağlamaz.
Cache-Control direktifinin anatomisi
Cache-Control başlığı virgülle ayrılmış direktiflerden oluşur. Görsel dosyaları için en sık karşılaşılan kombinasyonlar birkaç temel direktifi farklı biçimlerde bir araya getirir.
max-age=N direktifi, kaynağın N saniye boyunca geçerli sayılacağını belirtir. Tarayıcı bu süre içinde sunucuya gitmez. Bir yıl için max-age=31536000 kullanılır; bu değer pratikte "görsel değişmeyecek, önbellekte tut" anlamına gelir.
s-maxage=N yalnızca paylaşımlı önbellekler için geçerlidir; tarayıcı bu direktifi görmezden gelir. CDN katmanını ayrıca kontrol etmek istediğinizde s-maxage ile tarayıcı ve CDN davranışını birbirinden bağımsız ayarlayabilirsiniz. max-age=3600, s-maxage=86400 yazdığınızda tarayıcı görseli bir saat tutar, CDN ise bir gün tutar.
immutable direktifi, tarayıcıya "süre dolmadan bile doğrulama isteme" mesajı gönderir. Normalde tarayıcı önbelleğe aldığı bir kaynağı yenileme anında koşullu bir istekle doğrular (If-None-Match veya If-Modified-Since). immutable bunu engeller. Firefox ve Chrome bu direktifi destekler. Content hash ile sürümlenmiş görsellerde, yani dosya adı değişmeden görsel hiçbir zaman değişmeyecekse, immutable gereksiz ağ trafiğini ortadan kaldırır.
no-store önbelleği tamamen kapatır. Görsel her istekte yeniden indirilir. Kişiye özel fotoğraflar, anlık önizlemeler veya içeriğin tarayıcıda iz bırakmaması gereken senaryolar dışında görseller için bu direktif nadiren doğru seçimdir.
ETag ve koşullu istekler
Önbellek süresi dolduğunda tarayıcı sunucuya geri döner, ama mutlaka dosyayı yeniden indirmez. Sunucu dosyayı ilk gönderirken yanıta bir ETag değeri eklemişse, tarayıcı sonraki istekte bu değeri If-None-Match başlığıyla gönderir. Sunucu dosyanın değişmediğini anlarsa 304 Not Modified yanıtı döner; içerik transfer edilmez.
Bu mekanizma bant genişliğini korur. Büyük bir JPEG için 304 yanıtı birkaç bayt HTTP başlığından ibarettir. Sunucu ETag üretmiyorsa Last-Modified başlığı ve If-Modified-Since ile aynı mantık çalışır. Nginx ve Apache varsayılan yapılandırmada her ikisini de üretir; ancak bazı CDN kurulumları veya proxy yapılandırmaları bu başlıkları soyabilir.
ETag doğrulaması önbellek süresini uzatmaz. Tarayıcı önce max-age süresine bakar; süre dolduysa doğrulama isteği gönderir. Görsel değişmemişse 304 alır ve önbellek süresini sıfırdan başlatır. Görsel değişmişse 200 ile yeni içerik gelir.
URL sürümleme: önbelleği geçersiz kılmanın tek güvenilir yolu
Önbellek geçersiz kılma (cache invalidation) iki şekilde yapılır: sunucu tarafından veya URL değişikliğiyle. Sunucu taraflı geçersiz kılma CDN panelinden "önbelleği temizle" düğmesine basmak anlamına gelir; tarayıcı önbelleklerini hiçbir şekilde etkilemez. URL değişikliği ise hem CDN hem tarayıcı için yeni bir kaynak anlamına gelir.
Content hash sürümlemesi bu yüzden en sağlam yoldur. Yapı aracı (webpack, Vite, Parcel) her görsel için içerik parmak izi hesaplar ve dosya adına ekler: hero-a3f9c2.webp. Görsel değiştiğinde hash değişir, URL değişir, önbellek devreye girmez. Eski URL zaten başka bir dosyayı işaret eder; silinmesi bile gerekmez.
Sorgu parametresiyle sürümleme (hero.webp?v=2) bazı CDN'ler tarafından görmezden gelinebilir. CDN, sorgu parametresini önbellek anahtarının parçası saymak yerine yok varsayabilir ve eski içeriği döndürmeye devam edebilir. Güvenilir CDN'ler bunu doğru yapar; ancak hangi davranışı sergileyeceğini doğrulamak için CDN dokümantasyonunu kontrol etmek gerekir. Dosya adını değiştirmek her durumda çalışır.
Tarih tabanlı sürümleme (hero-2026-05.webp) içerik hash'inden daha az güvenilirdir. Aynı ay içinde iki farklı görsel aynı URL'yi paylaşabilir; bu durumda tarayıcı değişikliği görmez.
Nginx ve Apache yapılandırması
Statik dosya sunucularında Cache-Control başlığını dosya türüne göre ayarlamak standarttır. Nginx'te bir location bloğu veya map direktifiyle, Apache'de .htaccess veya VirtualHost bloğunda yapılır.
Nginx için tipik bir görsel yapılandırması:
location ~* \.(webp|avif|jpg|jpeg|png|gif|svg|ico)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
}
expires 1y direktifi Expires başlığını da ekler; eski HTTP/1.0 istemcilere geriye dönük uyumluluk sağlar. Modern istemciler Cache-Control başlığını tercih eder.
Apache'de mod_expires ve mod_headers etkin olmalıdır:
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/avif "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
</IfModule>
<IfModule mod_headers.c>
<FilesMatch "\.(webp|avif|jpg|jpeg|png|gif|svg|ico)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>
</IfModule>
Sık değişen görseller için, örneğin editörün her hafta güncellediği öne çıkan fotoğraflar için, ya URL'yi her seferinde değiştirin ya da max-age değerini düşük tutun. Her ikisini birden yapmak gerekmiyor; URL sürümleme varsa max-age bir yıl olabilir.
CDN önbellek davranışı ve başlık önceliği
CDN'ler kendi önbelleklerini yönetmek için genellikle kaynak sunucunun gönderdiği başlıklara uyar. Ancak her CDN bunu aynı biçimde yapmaz. Bazı sağlayıcılar Cache-Control başlığını olduğu gibi iletir, bazıları paneldeki TTL ayarına öncelik verir, bazıları ise kaynak başlığını CDN katmanında geçersiz kılmanıza izin verir.
CDN katmanında içeriği ayrı tutmak istiyorsanız s-maxage kullanın. Tarayıcı max-age'e uymaya devam eder; CDN ise s-maxage'e göre içeriği ne kadar süre tutacağına karar verir. Böylece CDN'yi daha uzun, tarayıcıyı daha kısa tutabilirsiniz; CDN panelinde manuel müdahaleye gerek kalmaz.
Vary: Accept başlığı, CDN'e aynı URL için farklı formatlar sunulduğunu bildirir. Tarayıcı WebP destekliyorsa WebP, desteklemiyorsa JPEG alır; ikisi aynı URL'den gelir. CDN'nin her ikisini de önbellekte tutması için Vary: Accept başlığının varlığına ihtiyaç vardır; yoksa CDN ilk gelen formatı tüm ziyaretçilere sunabilir.
Bazı CDN'ler Vary başlığını önbellek anahtarı olarak destekler, bazıları desteklemez veya farklı bir yapılandırma gerektirir. Görsel format müzakeresi yapıyorsanız CDN'nizin Vary: Accept ile nasıl davrandığını test edin.
Süresi dolan önbellek ve stale-while-revalidate
Önbellek süresi dolduğunda tarayıcı sunucuya doğrulama isteği gönderir. Bu isteğin tamamlanması sırasında kullanıcı bekliyorsa, görsel yeniden indirilene kadar sayfa o alanı boş gösterebilir. Görseller için bu senaryo metin kaynaklarına kıyasla daha görünür bir deneyim sorunudur.
stale-while-revalidate=N direktifi bu boşluğu kapatır. Önbellek süresi dolduğunda tarayıcı hâlâ eski içeriği gösterir; arka planda sessizce doğrulama isteği gönderir. N saniye içinde yeni içerik gelirse bir sonraki istekte kullanılır. Kullanıcı beklemez.
Cache-Control: public, max-age=86400, stale-while-revalidate=3600
Görseller için bu direktif en çok orta vadeli önbellek sürelerinde, yani birkaç gün ile birkaç hafta arasında, işe yarar. Zaten bir yıllık max-age ve içerik hash'i kullanan bir yapıda stale-while-revalidate eklemenin anlamlı bir katkısı olmaz; çünkü görsel URL değiştiğinde zaten yeni kaynak olarak ele alınır.
Uzun önbellek ne zaman yanlış tercihtir
İçerik hash olmadan uzun max-age kullanmak tehlikelidir. Görseli sunucuda değiştirseniz bile ziyaretçilerin büyük çoğunluğu önbellekteki eski sürümü görmeye devam eder. CDN önbelleğini temizlemiş olsanız da tarayıcı önbelleğine ulaşamazsınız.
Sık güncellenen görseller, özellikle fiyat listesi fotoğrafları, promosyon afişleri veya stok durumuna göre değişen ürün görselleri, için kısa bir max-age veya URL sürümleme zorunludur. Kısa max-age seçilirse, örneğin max-age=3600, her saatte bir doğrulama isteği gider; ETag ile 304 yanıtı alınırsa bu maliyet düşük kalır. Ancak yüksek trafikli sitelerde bu ek istek hacmini CDN ile absorbe etmek daha iyi bir tercihtir.
Kullanıcıya özel görseller, profilden fotoğraflar veya üyelere özel içerikler, public direktifi yerine private kullanmalıdır. Cache-Control: private, max-age=3600 tarayıcının önbelleğe almasına izin verir ama CDN ve ara proxy'lerin almamasını sağlar. Bunu ihmal etmek, bir kullanıcının özel görselinin başka bir kullanıcıya CDN üzerinden sunulmasına yol açabilir.
Görsel önbellekleme stratejisi tek başına bir performans kazanımı değil, dağıtım altyapısının bir parçasıdır. Cache-Control direktifleri, ETag doğrulaması ve URL sürümleme birlikte çalıştığında hem hız hem de güncelleme güvenilirliği birbirini baltalamak zorunda kalmaz. Yapı süreciniz içerik hash'i üretemiyorsa, sorgu parametresiyle bile olsa bir sürümleme mekanizması eklemek, uzun önbellek süresiyle açık bırakmaktan her zaman daha iyidir.
CDN panelindeki varsayılan TTL değerini kontrol etmeden sunucu başlıklarına güvenmek de bir tuzaktır. Bazı sağlayıcılar panel ayarını sunucu başlığının önüne koyar; yapılandırmanızın gerçekten uygulandığını doğrulamak için tarayıcının geliştirici araçlarından yanıt başlıklarını incelemeniz yeterlidir.