De meeste mensen kennen alleen de 301 en de 302. Toch zijn er nog twee redirects die je af en toe nodig hebt: de 307 en de 308. Ze doen hetzelfde als hun bekendere broers, met één belangrijk verschil. Een formulier of API-verzoek dat met POST wordt verstuurd, blijft ook na de redirect een POST.
Het probleem met 301 en 302
Een browser kan op verschillende manieren een verzoek doen. Met GET haal je een pagina op. Met POST stuur je gegevens mee, bijvoorbeeld de inhoud van een contactformulier of een bestelling.
Krijgt een browser op een POST-verzoek een 301 of 302 terug, dan maken de meeste browsers van het vervolgverzoek een GET. De gegevens die je verstuurde, gaan dan verloren. Dat gedrag stond oorspronkelijk niet zo in de standaard, maar browsers deden het massaal en de standaard heeft het later toegestaan.
Voor een gewone webpagina merk je daar niets van. Voor een formulier dat naar een nieuw adres is verhuisd, of een API-endpoint dat een andere URL krijgt, gaat het wel mis: de server krijgt een leeg verzoek binnen.
Wat doen 307 en 308?
Bij een 307 of 308 moet de browser het vervolgverzoek met dezelfde methode doen. Een POST blijft een POST, en de body wordt opnieuw meegestuurd naar het nieuwe adres. Een PUT blijft een PUT, een DELETE blijft een DELETE.
- 307 Temporary Redirect is de tijdelijke variant, de strikte versie van een 302.
- 308 Permanent Redirect is de permanente variant, de strikte versie van een 301.
Alle redirects naast elkaar
| Code | Naam | Permanent? | Mag de methode veranderen? |
|---|---|---|---|
| 301 | Moved Permanently | Ja | Ja, POST wordt in de praktijk GET |
| 302 | Found | Nee | Ja, POST wordt in de praktijk GET |
| 303 | See Other | Nee | Altijd GET |
| 307 | Temporary Redirect | Nee | Nee |
| 308 | Permanent Redirect | Ja | Nee |
De 303 valt een beetje buiten de rij. Die gebruik je bewust om na een POST door te sturen naar een gewone pagina, zoals een bedankpagina. Zo voorkom je dat een bezoeker het formulier opnieuw verstuurt als hij de pagina ververst.
Waar komen 307 en 308 vandaan?
De 303 en 307 kwamen er bij HTTP/1.1, juist om de onduidelijkheid rond 302 op te lossen. De 308 kwam later: die werd vastgelegd in RFC 7538, als permanente tegenhanger van de 307. De andere codes waren toen beschreven in RFC 7231.
Tegenwoordig staan alle redirect-codes, inclusief 308, samen in RFC 9110, de huidige beschrijving van HTTP-semantiek. Die vervangt de oudere documenten. Voor jou verandert er inhoudelijk niets: de betekenis van de codes is gelijk gebleven.
Wanneer gebruik je ze?
Formulieren
Verhuist een pagina met een formulier naar een nieuw adres, en kunnen er nog formulieren of oude pagina’s naar het oude adres posten? Dan zorgt een 308 dat de ingevulde gegevens aankomen. Met een 301 zou de server alleen een lege GET zien.
API’s
Een API die verhuist naar een nieuw domein of pad, krijgt van allerlei clients nog verzoeken op het oude adres. Met een 308 komen POST-, PUT- en DELETE-verzoeken met hun body op de nieuwe plek aan. Let wel op: niet elke HTTP-client volgt redirects automatisch, en sommige stoppen bij een redirect naar een ander domein. Laat clients dus ook zelf hun URL bijwerken.
Webhooks
Diensten die webhooks sturen, doen dat bijna altijd met POST. Verandert het adres van je webhook-ontvanger, dan is een 307 of 308 de enige redirect die de payload behoudt. Of de afzender redirects volgt, verschilt per dienst. Het veiligste blijft de webhook-URL bij de afzender aan te passen en de redirect als vangnet te gebruiken.
Tijdelijk omleiden van een endpoint
Is een server tijdelijk in onderhoud en wil je verzoeken naar een andere server sturen, dan is een 307 de juiste keuze. De methode blijft gelijk en clients blijven het oude adres gebruiken zodra het weer beschikbaar is.
Instellen op je eigen server
In nginx werkt het net als een 301, alleen met een andere code:
location /api/ {
return 308 https://api.voorbeeld.nl$request_uri;
}
In Apache met mod_rewrite geef je de code mee aan de R-vlag:
RewriteEngine On
RewriteRule ^api/(.*)$ https://api.voorbeeld.nl/$1 [R=308,L]
Test daarna met een echt POST-verzoek, want een GET laat het verschil niet zien. Met curl volg je de redirect met -L, en zorgt --post301 of --post302 ervoor dat curl ook bij een 301 of 302 de POST behoudt. Bij een 307 of 308 is dat niet nodig:
curl -i -L -X POST -d "naam=test" http://voorbeeld.nl/api/aanmelden
De 307 die je in DevTools ziet
Open je de netwerktab van je browser en typ je http:// voor een domein, dan zie je soms een 307 met de tekst "Internal Redirect" of "Non-Authoritative Reason: HSTS". Die komt niet van de server.
Het domein gebruikt dan HSTS (HTTP Strict Transport Security). Daarmee heeft de website eerder aan je browser gezegd: benader mij alleen via https. Je browser onthoudt dat en zet een http-adres meteen zelf om naar https, nog voordat er een verzoek de deur uit gaat. In DevTools wordt dat weergegeven als een 307, omdat de methode gelijk blijft.
Belangrijk om te weten bij het testen: je browser laat je dan niet zien wat de server zelf op http antwoordt. Gebruik daarvoor de redirect checker of curl, die geen HSTS-geheugen hebben.
curl -I http://voorbeeld.nl
307 en 308 voor SEO
Voor Google is de keuze simpel. Een 308 wordt behandeld als een 301: een permanente verhuizing, waarbij de nieuwe URL in de index komt. Een 307 wordt behandeld als een 302: tijdelijk, de oude URL blijft de canonieke.
Voor een domeinverhuizing of een gewone pagina kun je dus zonder bezwaar een 301 blijven gebruiken. Lees meer in de gids over de 301 redirect en de 302 redirect.
Bij elke redirect kies je zelf de statuscode: 301, 302, 307 of 308. Stuur je een domein door waar ook formulieren of API-verzoeken op binnenkomen, kies dan 308 voor een blijvende verhuizing of 307 voor een tijdelijke.