omeryanbas.com

Ömer Yanbaş

Genel Müdür, Ticofab Yazılım

WebArama

Tarayıcıda önbelleğe alınan 301, yeniden tasarımdan sonra siteyi nasıl kırıyor

Tarayıcılar kalıcı yönlendirmeyi süresiz saklar. Yeni site eski 301'i ters çevirirse geri dönen ziyaretçi döngüye girer. Teşhisi ve kalıcı çözümü.

Site yeni yapısıyla yayına alınır. Sahibi açar, bir bağlantıya tıklar ve tarayıcı "bu sayfa çalışmıyor" der. Sunucu tarafındaki her kontrol temizdir: durum kodları doğru, başlıklar doğru, sayfalar yerinde. Aynı adresi gizli sekmede açarsanız sorunsuz çalışır. Sorun sunucuda değildir. Tarayıcının aylar önce not aldığı ve bir daha hiç sorgulamadığı kalıcı bir yönlendirmedir.

Gerçekte ne oluyor

301 "bu taşınma kalıcı" demektir ve tarayıcılar bunu harfiyen uygular. Yanıtta açık bir önbellek başlığı yoksa tarayıcı süreyi kendisi tahmin eder, 301 için de hem Chrome hem Safari kaydı diske yazar. Aynı adres bir daha istendiğinde sunucuya sorulmaz, doğrudan hatırlanan hedefe gidilir.

Yön değişene kadar bunun zararı yoktur. Yeniden yapılan sitelerde en sık gördüğüm sıralama şu:

  1. Eski site / adresini 301 -> /index.html ile yanıtlıyordu, çünkü dizin dosyası öyle üretiliyordu.
  2. Ziyaretçiler bu yönlendirmeyi önbelleğinde biriktirdi.
  3. Yeni site temiz, / gerçek sayfa, /index.html ise artık. Akla gelen düzeltme 301 /index.html -> / oluyor.
  4. Geri dönen ziyaretçi / ister, önbellek /index.html der, sunucu / der, önbellek yine /index.html der. Tarayıcı pes edene kadar döngü sürer.

Yeni ziyaretçi bunu hiç görmez. Arama motoru botları da genelde görmez, çünkü yanlarında bir yıllık gezinme geçmişi taşımazlar. Sorunu yaşayanlar sitenin sahibi, ekip ve düzenli okuyuculardır. Yani olabilecek en kötü örneklem.

Nasıl görülür

İlk refleks curl çalıştırmaktır ve curl size her şeyin yolunda olduğunu söyler:

curl -sI https://ornek.com/ | head -3
# HTTP/2 200
# content-type: text/html; charset=utf-8
# cache-control: no-cache

Curl her çalıştığında boş önbellekle başlar, bu hatayı asla üretemez. Bunun yerine tarayıcıyı kullanın: ağ panelini açın ve "disable cache" seçeneğini kapalı tutun. Önbellekten gelen bir yönlendirme, ağ süresi olmayan ve (from disk cache) yazan 301 satırı olarak görünür.

Tekrar tekrar koşturabileceğiniz bir senaryo istiyorsanız betiğe dökün. Önce eski davranışı sunun, bir kez ziyaret edin, sonra sunucuyu yeni davranışa geçirip tıklayın:

// tek sunucu, iki davranış, tek tarayıcı profili
if (mode === 'old' && url === '/') return redirect(301, '/index.html');
if (mode === 'new' && url === '/index.html') return redirect(301, '/');

Önce eski kural ziyaret edildiğinde, yeni kural normal sekmede döngüyü her seferinde üretir. Düzeltmenizin işe yarayıp yaramadığını size söyleyecek test budur ve yazması bir dakika sürer.

Çözüm

Yönlendirmeyi ters çevirmeyi bırakın. Eski adresi gerçek sayfa olarak sunun, arama tarafını canonical etiketi taşısın:

# /index.html sayfanın kendisini döner, yönlendirme yok, döngü yok
location / {
  try_files $uri $uri/ =404;
}
<link rel="canonical" href="https://ornek.com/">

Arama motorları bu düzenden memnundur. Canonical etiketi zaten "bu iki adres aynı sayfa, şunu dizine al" demenin yoludur ve tarayıcının bir şeyi takip etmesini gerektirmez.

Sonra eski kaydı temizleyin. Clear-Site-Data: "cache" başlığı tarayıcıya o origin için HTTP önbelleğini bırakmasını söyler, önbelleğe alınmış yönlendirmeler dahil. Başlığı yalnızca ihtiyacı olan adreste gönderin ki normal ziyaret bunun bedelini ödemesin:

map $request_uri $clear_cache {
  "~^/index\.html"  '"cache"';
  default           "";
}

server {
  add_header Clear-Site-Data $clear_cache;
}

Boş değer nginx'in başlığı hiç göndermemesi demektir. Böylece / etkilenmez, /index.html ise arkasını bir kere toplayıp temizler.

Son olarak adres çubuğunu düzeltin. Ziyaretçi göremediği bir yönlendirmeyle eski adrese düştü, orada kalmasının bir anlamı yok:

if (location.pathname.endsWith('/index.html')) {
  history.replaceState(null, '', location.pathname.slice(0, -10) + location.search + location.hash);
}

Çalıştığını nasıl doğrularsınız

İki komut ve bir tıklama. Eski adres sayfayı ve temizlik başlığını döner, temiz adres bu başlığı dönmez:

curl -sI https://ornek.com/index.html | grep -i "HTTP/\|clear-site-data"
# HTTP/2 200
# clear-site-data: "cache"

curl -sI https://ornek.com/ | grep -ci clear-site-data
# 0

Ardından betiğe döktüğünüz senaryoyu tekrarlayın. İlk tıklama eski adresten geçip sayfaya düşer, ikinci tıklama doğrudan temiz adrese gider, çünkü eski kayıt artık yoktur.

Nelere dikkat etmeli

  • Clear-Site-Data yalnızca güvenli origin'de ve yalnızca listelediğiniz değerler için çalışır. Başlığı her sayfada göndermek her ziyarette fontları ve görselleri çöpe atar, kendi elinizle performans hatası üretmiş olursunuz.
  • Bu başlıkta Firefox desteği Chrome'un gerisinde kaldı. Onu çoğu kullanıcıya yardım eden bir temizlik olarak görün, sayfayı doğru yapan şey olarak değil. Doğru yapan şey, ters yönlendirme yerine 200 dönmektir.
  • Yönlendirme zincirleri de aynı sınıftan. /a adresini /b'ye, sonra /b'yi /c'ye gönderirseniz geri dönen ziyaretçi hiç test etmediğiniz bir yoldan geçebilir. Testi geçmişi olan bir profille yapın, sıfırdan profille değil.
  • Eski yönlendirmenin hedefi artık hiç sunmadığınız bir yolsa, tarayıcının size sormasını bekleyemezsiniz. O adreste en az bir sürüm boyunca geçerli bir yanıt bırakın.

Dersin kendisi hatadan küçük: kalıcı yönlendirme bir sözdür ve tarayıcılar sözleri bizim hatırladığımızdan uzun süre tutar. Eski bir yönlendirmenin yönünü değiştirmeden önce, bazı okuyucuların hâlâ eskisini taşıdığını varsayın ve o adrese geçerli bir yanıt bırakın. Taşımanın kalıcı olduğundan emin değilseniz 302 bedava bir esnekliktir. Temiz profille değil geçmişi olan bir tarayıcıyla kontrol etme alışkanlığı, "bende çalışıyor" diye geçiştirilen şaşırtıcı sayıda hatayı yakalar; aynı disiplin tahmin etmeden önce ölçmek için de geçerlidir.

Sorular ve cevaplar

Tarayıcı 301 yönlendirmesini ne kadar süre saklar?
Kendi bildiği kadar. Önbellek başlığı olmayan bir 301 sezgisel olarak önbelleğe alınabilir ve hem Chrome hem Safari bunu diske yazar. Kayıt tarayıcı kapanınca silinmez, yönlendirmeyi veren siteden daha uzun yaşayabilir. Tek güvenilir kısayol, yönlendirmeyi verirken açık bir cache başlığı eklemektir.
Neden bende bozuk, başkasında çalışıyor?
Temiz bir profilde o yönlendirme yoktur, tarayıcı bugün sunucu ne diyorsa onu yapar. Geri dönen ziyaretçide ise eski kalıcı yönlendirme diskte durur ve o adres için sunucuya hiç sorulmaz. Gizli sekmenin çalışıp normal sekmenin çalışmamasının sebebi de budur.
Clear-Site-Data kullanıcının her şeyini siler mi?
"cache" değeri yalnızca o origin için HTTP önbelleğini temizler. İçine önbelleğe alınmış yönlendirmeler, görseller ve fontlar girer. Çerezlere ve depolamaya dokunmaz, onları ayrıca istemeniz gerekir. Başlığı sadece ihtiyacı olan adreste gönderin, her sayfada değil.
Bu sorunu yaşamamak için 302 mi kullanmalıyım?
İleride geri alma ihtimaliniz varsa evet. 302 varsayılan olarak önbelleğe alınmaz, fikir değiştirmenin maliyeti olmaz. 301'i yalnızca gerçekten kalıcı taşımalarda, örneğin alan adı birleştirmede veya http'den https'e geçişte kullanın.