Cos'e HTTP 303 See Other
Il codice HTTP 303 See Other indica al client che la risposta alla sua richiesta puo essere trovata a un'URL diverso, ottenibile via GET. La sua peculiarita: forza esplicitamente il metodo GET nella richiesta successiva, indipendentemente dal metodo originale (POST, PUT, DELETE).
Il pattern Post/Redirect/Get (PRG)
E uno dei pattern web più importanti per evitare problemi di doppia submission:
- L'utente compila un form e fa POST (es.
POST /ordini). - Il server elabora la richiesta (crea l'ordine, salva su DB).
- Il server risponde con
303 See OthereLocation: /ordini/123. - Il browser fa automaticamente
GET /ordini/123. - L'utente vede la pagina di conferma. Se ricarica (F5), ripete solo il GET, non il POST.
Senza PRG, premere F5 dopo l'invio rieseguirebbe la POST, creando ordini duplicati.
Differenze con 302 e 307
| Codice | Cambia metodo? | Quando usarlo |
|---|---|---|
| 302 Found | De facto si (POST -> GET) ma standard ambiguo | Redirect generico |
| 303 See Other | Si, sempre GET | PRG, conferme post-submit |
| 307 Temp Redirect | No, preserva metodo | Quando vuoi mantenere POST/PUT |
Esempio pratico Laravel
public function store(Request $request) {
$order = Order::create($request->validated());
return redirect()->route('orders.show', $order)
->setStatusCode(303);
}
Esempio Express.js
app.post('/comments', async (req, res) => {
const comment = await Comment.create(req.body);
res.redirect(303, '/comments/' + comment.id);
});
Quando usare il 303
- Dopo form submission: per evitare doppie creazioni con il refresh.
- Dopo PUT/DELETE: per indicare la pagina di stato risultante.
- Conferma azioni: pagine "operazione riuscita" con link alla risorsa.
- API HATEOAS: per indicare la risorsa "next" da consultare via GET.
Comportamento browser
Tutti i browser moderni rispettano correttamente il 303: dopo un POST, anche se la specifica RFC sarebbe stata altrimenti ambigua, eseguono GET sulla nuova URL. Anche fetch/XHR si comportano così quando redirect: 'follow'.
Cache-Control
Le risposte 303 NON sono cacheable per default. La pagina di destinazione (raggiunta via GET) puo invece avere le sue policy di caching. Il 303 va trattato sempre come decisione runtime del server.
Body della risposta
Il 303 puo contenere un body HTML con un link manuale alla nuova URL, come fallback per client che non seguono redirect automaticamente:
HTTP/1.1 303 See Other
Location: /orders/123
Content-Type: text/html
<html><body>
<p>Ordine creato. <a href="/orders/123">Visualizza</a></p>
</body></html>
303 in API REST
Nel pattern HATEOAS, dopo un POST che crea una risorsa, alcuni stili API preferiscono:
- 201 Created + Location: standard più diffuso, il client costruisce la URL nel body.
- 303 See Other: meno comune ma utile per client che vogliono fetchare immediatamente la risorsa creata via GET.
Sicurezza
Il 303 evita repost involontari e quindi anche alcuni problemi di sicurezza CSRF amplificati dalla ripetizione di azioni distruttive. Combinalo sempre con token CSRF e con SameSite=Strict sui cookie di sessione.
Considerazioni sui motori di ricerca
Il 303 e trattato come redirect temporaneo: non trasferisce ranking come fa il 301. Usalo nel flusso applicativo (POST/PUT/DELETE), non per cambi strutturali di URL pubbliche. Per quelle, sempre 301.
303 e API HATEOAS
Nelle API HATEOAS, dopo un POST che crea una risorsa, il client potrebbe voler fetchare immediatamente lo stato finale. Il 303 e elegante in questo caso: client fa POST /orders, server salva e risponde 303 Location /orders/123, client fa automaticamente GET /orders/123 ricevendo la rappresentazione completa.
Differenza con 201 Created
Il 201 Created include nel body la rappresentazione della risorsa appena creata (no extra round-trip). Il 303 forza un GET separato. Il 201 e più efficiente; il 303 e più "puro" nel modello REST. Scelta progettuale a seconda della tua audience.
Combinare 303 e CSRF
Il pattern PRG si combina elegantemente con protezione CSRF: il token CSRF e nel form POST, viene validato server-side; se valido, redirect 303 verso la pagina di conferma. Il token non viene mai "leaked" tramite URL.
303 in REST: PUT idempotente
Dopo PUT /resource/42 idempotente, il server puo rispondere 303 verso /resource/42 stesso, forzando il client a fetchare via GET la nuova rappresentazione. Utile quando il server ha applicato trasformazioni (normalizzazione, calcolo campi derivati).
Browser back/forward dopo 303
Il pattern PRG con 303 risolve anche il problema del "back" dopo submit: la storia del browser contiene solo GET, quindi premere indietro non rifa la POST. Esperienza utente molto più pulita rispetto al puro 200 OK dopo POST.
303 in flusso checkout
Tipico checkout e-commerce: utente preme "Conferma ordine" (POST), backend processa pagamento, ritorna 303 verso /ordine/123/conferma. Vantaggi: ricaricare la pagina (F5) NON ri-processa il pagamento; bookmark della pagina conferma punta a stato consultabile; tracking analytics ben definito.
303 in DELETE flow
Dopo DELETE su /post/42, il server puo rispondere 303 verso /posts (lista). Così il client torna automaticamente alla lista aggiornata senza la risorsa cancellata. Pattern raro ma elegante in app server-rendered.
303 vs 200
Alcuni API stili preferiscono 200 con body contenente il risultato finale (single round-trip). Altri preferiscono 303 + GET successivo (due round-trip ma stato esplicito). Scelta tra latency e cleanliness.
303 in REST puro
Il REST puro suggerisce: POST crea risorsa, ritorna 201 Created con Location. Se vuoi forzare un GET successivo per ottenere la rappresentazione, allora 303 e l'opzione canonica. 201 e più efficiente, 303 e più HATEOAS-correct.
Hai bisogno di aiuto?
Se il tuo sito mostra errori HTTP, il team di G Tech Group puo aiutarti. Contattaci tramite il modulo di contatto.