Chyba vypadá takto. Integrace pošle POST na váš endpoint. Endpoint funguje, routa existuje, ručně se všechno ověří. Jenže v logu je GET na routu, která přijímá pouze POST, zodpovězený 404 nebo 405.
Příčina je téměř vždy stejná: mezi klientem a endpointem stojí přesměrování s kódem 301 nebo 302. A tyto kódy klienta k zachování metody nezavazují.
Ověření zabere deset sekund:
curl -sS -o /dev/null -L -d 'test=1' \
-w 'metoda po přesměrování: %{method}\n' \
'https://httpbingo.org/redirect-to?url=/anything&status_code=301'
Výstup: metoda po přesměrování: GET. Tělo požadavku se ztrácí spolu s ní.
Změňte ve stejném příkazu 301 na 308 a dostanete POST. Jediný rozdíl je stavový kód.
Pět kódů, dvě vlastnosti
Přesměrování se liší ve dvou nezávislých osách: zda jsou trvalá nebo dočasná, a zda přežije metoda požadavku.
| Kód | Název | Trvalost | Metoda zachována |
|---|---|---|---|
| 301 | Moved Permanently | trvalé | ne |
| 302 | Found | dočasné | ne |
| 303 | See Other | — | ne, vždy GET |
| 307 | Temporary Redirect | dočasné | ano |
| 308 | Permanent Redirect | trvalé | ano |
Všimněte si symetrie: 307 je 302 se zárukou metody a 308 je 301 se zárukou metody.
Odkud ten zmatek pochází
Formálně specifikace nikdy nevyžadovala měnit metodu u 301 a 302. Jenže rané prohlížeče a klienti to dělali přesně takto, a než si nesouladu někdo všiml, celý web už tak fungoval.
Chování tedy bylo zakotveno jako přípustné: RFC 9110, platná specifikace sémantiky HTTP, dovoluje klientovi u 301 a 302 nahradit POST za GET. Dovoluje, ale nevyžaduje — chování tak zůstává na klientovi a nelze se na ně spolehnout.
Aby existovala jednoznačná varianta, byly zavedeny kódy 307 a 308. U nich je změna metody zakázána: klient musí požadavek zopakovat se stejnou metodou i stejným tělem. Kód 308 je definován ve vlastním RFC 7538, referenční popis nabízí i dokumentace MDN.
Praktický závěr: 301 a 302 jsou bezpečné jen tam, kde je požadavek jistě GET. Všude, kam může dorazit POST, jsou potřeba 307 nebo 308.
Druhá past: trvalá přesměrování se kešují
Na tuhle se zapomíná ještě častěji než na problém s metodou.
301 a 308 prohlašují přesun za trvalý a prohlížeč je smí kešovat dlouho — někdy až do chvíle, kdy uživatel vymaže keš. Poté se serveru už prostě nikdo neptá.
Z toho plyne pravidlo: omylem nasazené 301 se prakticky nedá vzít zpět. Konfiguraci opravíte, ale návštěvníci, kteří starou odpověď už dostali, budou přesměrováváni dál. U 302 a 307 tenhle problém nenastává — jsou z definice dočasné.
Praktická rada: dokud schéma přesunů není ustálené, používejte dočasné kódy. Povýšit později 302 na 301 je snadné; opačná cesta nikoli.
Co vybrat
Stránka se natrvalo přestěhovala a přijímá jen GET → 301. Klasický případ: stará URL článku, změna struktury adres.
Totéž, ale endpoint přijímá POST → 308. Sem patří API, webhooky a formuláře.
Cíl se mění dočasně, jen GET → 302.
Dočasně a metoda musí zůstat zachována → 307.
Po POST poslat uživatele na stránku s výsledkem → 303. To je vzor POST/Redirect/GET: záměrně mění požadavek na GET, aby obnovení stránky formulář neodeslalo znovu. Tady je změna metody účelem, nikoli vadou.
Kde to v praxi selhává
Přesměrování http→https před API. Nejčastější a nejnepříjemnější případ. Klient je nastaven na http://, server odpoví 301 mířícím na https://, metoda se ztratí. Příznak: GET v logu na POST routě. Řeší se náhradou 301 za 308.
Kanonizace hostitele. Přesměrování z www na bez www (nebo naopak) se obvykle staví jako 301. Pro stránky v pořádku, ale pokud na témže hostiteli žije API, platí přesně stejný problém.
Odeslání formulářů. Formulář se odesílá na adresu, která přesměrovává. Uživatel vidí, že „se nic nestalo", protože data se k handleru nikdy nedostala.
Webhooky. Externí služba posílá POST na adresu, kterou jste jí kdysi dali. Pokud se ta adresa přesunula za 301, webhooky tiše přestanou fungovat, zatímco v logu odesílatele svítí úspěšná odpověď na přesměrování.
Všechny čtyři případy mají společný rys: endpoint je zdravý, ale požadavek se k němu nedostane v původní podobě. Diagnostika proto míří špatným směrem — hledá se chyba v handleru, a přitom je v konfiguraci webserveru.
Proč zkracovače používají 302
Krátký odkaz vrací téměř vždy 302 a jde o vědomou volbu, ne o nedbalost.
Důvodem je trvalost, nikoli metoda: cíl krátkého odkazu se může změnit. Použít 301 by znamenalo dovolit prohlížečům zakešovat skok natrvalo, a po změně cíle by část návštěvníků nadále přistávala na staré adrese. Metoda tu roli nehraje — krátké odkazy se procházejí požadavky GET.
Samotný mechanismus popisuje článek o tom, jak fungují zkracovače odkazů.
Co volba kódu nemění
Dva rozšířené omyly.
Odkazová síla. Volba mezi 301 a 302 nemá vliv na předávání síly — Google to potvrdil už v roce 2016. Podrobné zpracování najdete v článku předávají krátké odkazy odkazovou sílu?.
Výběr kanonické adresy. Přesměrování a rel="canonical" řeší různé věci: přesměrování stahuje adresu z oběhu, canonical nechává obě dostupné a označuje tu hlavní. Kdy použít co, popisuje průvodce canonicalem.
Krátký kontrolní seznam
- Na routách přijímajících
POSTpoužívat 307 nebo 308, nikoli 302 a 301. - Přesměrování http→https kontrolovat zvlášť: bývá nastaveno plošným pravidlem a na API se zapomene.
- Dokud schéma není ustálené, dočasné kódy. 301 a 308 se kešují a sotva se dají vrátit.
- Po zpracování formuláře použít 303 — to je správné chování, ne chyba.
- Řetězce zkrátit na jediný skok: každý skok navíc přidává latenci i riziko.