Hata şöyle görünür. Bir entegrasyon uç noktanıza POST gönderir. Uç nokta çalışıyordur, rota yerindedir, elle bakıldığında her şey normaldir. Ama günlüklerde yalnızca POST kabul eden bir rotaya gelen GET görünür ve yanıt 404 ya da 405'tir.
Sebep neredeyse her zaman aynıdır: istemciyle uç nokta arasında 301 veya 302 kodlu bir yönlendirme durmaktadır. Ve bu kodlar istemciyi yöntemi korumaya zorlamaz.
Doğrulaması on saniye sürer:
curl -sS -o /dev/null -L -d 'test=1' \
-w 'yönlendirme sonrası yöntem: %{method}\n' \
'https://httpbingo.org/redirect-to?url=/anything&status_code=301'
Çıktı: yönlendirme sonrası yöntem: GET. İstek gövdesi de birlikte kaybolur.
Aynı komutta 301 yerine 308 yazın, POST alırsınız. Tek fark durum kodudur.
Beş kod, iki özellik
Yönlendirmeler birbirinden bağımsız iki eksende ayrışır: kalıcı mı geçici mi, ve istek yöntemi korunuyor mu.
| Kod | Ad | Kalıcılık | Yöntem korunur |
|---|---|---|---|
| 301 | Moved Permanently | kalıcı | hayır |
| 302 | Found | geçici | hayır |
| 303 | See Other | — | hayır, her zaman GET |
| 307 | Temporary Redirect | geçici | evet |
| 308 | Permanent Redirect | kalıcı | evet |
Simetriye dikkat edin: 307, yöntem garantili bir 302'dir; 308 ise yöntem garantili bir 301.
Bu karışıklık nereden geliyor
Biçimsel olarak spesifikasyon 301 ve 302'de yöntemin değiştirilmesini hiçbir zaman şart koşmadı. Ama ilk tarayıcılar ve istemciler tam olarak bunu yapıyordu ve uyumsuzluk fark edildiğinde bütün web çoktan böyle çalışıyordu.
Böylece bu davranış «izin verilen» olarak kayda geçti: HTTP semantiğinin yürürlükteki spesifikasyonu RFC 9110, istemcinin 301 ve 302'de POST'u GET ile değiştirmesine izin veriyor. İzin veriyor ama zorunlu kılmıyor — yani davranış istemcinin insafına kalıyor ve ona güvenilemez.
Kesin bir seçenek sunmak için 307 ve 308 getirildi. Onlarda yöntemi değiştirmek yasaktır: istemci isteği aynı yöntem ve aynı gövdeyle yinelemek zorundadır. 308 kodu kendi RFC 7538 belgesinde tanımlıdır; başvuru niteliğinde açıklama MDN dokümantasyonunda da bulunur.
Pratik sonuç: 301 ve 302 yalnızca isteğin kesinlikle GET olduğu yerlerde güvenlidir. POST gelme ihtimali olan her yerde 307 ya da 308 gerekir.
İkinci tuzak: kalıcı yönlendirmeler önbelleğe alınır
Bu, yöntem sorunundan da sık unutulur.
301 ve 308 taşınmayı kalıcı ilan eder ve tarayıcının bunları uzun süre önbelleğe alma hakkı vardır — bazen kullanıcı önbelleğini temizleyene kadar. Ondan sonra sunucuya artık sorulmaz bile.
Buradan şu kural çıkar: yanlışlıkla konmuş bir 301'i geri almak neredeyse imkânsızdır. Yapılandırmayı düzeltirsiniz, ama eski yanıtı çoktan almış ziyaretçiler yönlendirilmeye devam eder. 302 ve 307'de böyle bir sorun yoktur — onlar tanımı gereği geçicidir.
Pratik öneri: taşınma şeması oturana kadar geçici kodları kullanın. Sonradan 302'yi 301'e yükseltmek kolaydır; tersi değil.
Ne seçmeli
Sayfa kalıcı olarak taşındı ve yalnızca GET kabul ediyor → 301. Klasik durum: eski makale adresi, adres yapısının değişmesi.
Aynısı, ama uç nokta POST kabul ediyor → 308. API'ler, webhook'lar ve formlar buraya girer.
Hedef geçici olarak değişiyor, yalnızca GET → 302.
Geçici ve yöntem korunmak zorunda → 307.
POST sonrası kullanıcıyı bir sonuç sayfasına göndermek → 303. Bu, POST/Redirect/GET kalıbıdır: isteği bilerek GET'e çevirir ki sayfayı yenilemek formu yeniden göndermesin. Burada yöntem değişimi amacın kendisidir, kusur değil.
Pratikte nerede kırılıyor
API'nin önündeki http→https yönlendirmesi. En yaygın ve en can sıkıcı durum. İstemci http:// ile yapılandırılmıştır, sunucu https:// adresine 301 döner, yöntem kaybolur. Belirti: günlüklerde POST rotasına gelen GET. 301'i 308 ile değiştirerek çözülür.
Ana makine kanonikleştirmesi. www'dan www'suza (ya da tersi) yönlendirme genelde 301 olarak kurulur. Sayfalar için sorun yok, ama aynı ana makinede bir API yaşıyorsa tam olarak aynı sorun geçerlidir.
Form gönderimi. Form, yönlendirme yapan bir adrese gönderilir. Kullanıcı «hiçbir şey olmadı» görür, çünkü veriler işleyiciye hiç ulaşmamıştır.
Webhook'lar. Dış bir servis, bir zamanlar verdiğiniz adrese POST gönderir. O adres bir 301'in arkasına taşındıysa webhook'lar sessizce çalışmayı bırakır, gönderenin günlüklerinde ise yönlendirmeye verilen başarılı yanıt görünür.
Dördünün de ortak imzası var: uç nokta sağlamdır ama istek ona özgün biçiminde ulaşmaz. Bu yüzden teşhis yanlış yöne gider — hata işleyicide aranır, oysa web sunucusu yapılandırmasındadır.
Kısaltma servisleri neden 302 kullanır
Kısa bağlantı neredeyse her zaman 302 döner ve bu bilinçli bir tercihtir, ihmal değil.
Sebep kalıcılıkla ilgilidir, yöntemle değil: kısa bağlantının hedefi değişebilir. 301 kullanmak, tarayıcıların bu sıçramayı kalıcı olarak önbelleğe almasına izin vermek olurdu ve hedef değiştikten sonra ziyaretçilerin bir kısmı eski adrese düşmeye devam ederdi. Yöntem burada önemsizdir — kısa bağlantılara GET istekleriyle gidilir.
Mekanizmanın kendisi URL kısaltıcı nasıl çalışır yazısında ayrıca ele alınıyor.
Kod seçiminin değiştirmediği şeyler
Yaygın iki yanılgı.
Bağlantı değeri. 301 ile 302 arasındaki seçim değer aktarımını etkilemez — Google bunu 2016'da doğruladı. Ayrıntılı ele alış kısa bağlantılar bağlantı değeri aktarır mı? yazısında.
Kanonik adresin seçimi. Yönlendirme ile rel="canonical" farklı sorunları çözer: yönlendirme bir adresi dolaşımdan çıkarır, canonical ikisini de erişilebilir bırakıp asıl olanı belirtir. Hangisinin ne zaman kullanılacağı canonical rehberinde anlatılıyor.
Kısa kontrol listesi
POSTkabul eden rotalarda 302 ve 301 değil, 307 veya 308 kullanın.- http→https yönlendirmesini ayrıca kontrol edin: genellikle toptan bir kuralla konur ve API unutulur.
- Şema oturana kadar geçici kodlar. 301 ve 308 önbelleğe alınır ve neredeyse geri alınamaz.
- Form işlendikten sonra 303 kullanın — bu doğru davranıştır, hata değil.
- Zincirleri tek sıçramaya indirin: her fazladan sıçrama hem gecikme hem risk ekler.