Cos'è il redirect 308
Il 308 Permanent Redirect è un codice di stato HTTP standardizzato nella RFC 7538 (2015). Dice al client: «La risorsa richiesta si è spostata permanentemente a un nuovo URL. Ripeti la richiesta lì con lo stesso metodo e lo stesso body». La parola chiave è «permanentemente»: a differenza del 307, che è temporaneo, il 308 è permanente e segnala ai motori di ricerca di aggiornare l'indice e trasferire il valore dei link.
Il codice 308 colma una lacuna della specifica HTTP: prima della sua esistenza gli sviluppatori affrontavano un dilemma — il 301 è permanente ma i browser di fatto cambiano POST in GET; il 307 preserva il metodo ma solo per spostamenti temporanei. Il 308 combina la permanenza del 301 con la garanzia di preservazione del metodo del 307.
308 vs 301 vs 307 vs 302: differenze chiave
I quattro codici di redirect differiscono lungo due assi: permanenza e preservazione del metodo HTTP.
- 301 Moved Permanently — redirect permanente, trasferisce il valore dei link. Il metodo dovrebbe tecnicamente essere preservato, ma i browser degradano POST→GET (comportamento ereditato da HTTP/1.0).
- 302 Found (temporaneo) — redirect temporaneo, nessun trasferimento di valore. Il metodo è di fatto cambiato POST→GET nella maggior parte dei browser.
- 307 Temporary Redirect — redirect temporaneo, nessun trasferimento di valore. Il metodo è rigorosamente preservato (POST resta POST).
- 308 Permanent Redirect — redirect permanente, trasferisce il valore dei link. Il metodo è rigorosamente preservato. L'equivalente del 301 amico di API e form.
Quando usare il 308
- Migrazione permanente di endpoint API: quando i client inviano PUT/PATCH/DELETE e devi spostare definitivamente l'endpoint a un nuovo indirizzo senza perdere il body della richiesta.
- Cambio permanente dell'URL di un form: quando cambi definitivamente l'indirizzo di un form di registrazione o di checkout, preservando i dati POST.
- Upgrade di versione dell'API: migrazione da /api/v1/ a /api/v2/ quando la vecchia versione viene ritirata definitivamente, preservando il metodo della richiesta.
- Upgrade a HTTPS per endpoint POST: quando sposti permanentemente form e API da HTTP a HTTPS dove preservare metodo e body della richiesta è critico.
- Ristrutturazione delle route dell'applicazione: quando sposti permanentemente i gestori dei form a una nuova struttura dentro l'applicazione.
Redirect 308 e SEO
Dal punto di vista dei motori di ricerca, il 308 è un redirect permanente equivalente al 301. Google e Bing trasferiscono il valore dei link (PageRank) attraverso il 308: l'URL originale esce dall'indice e la destinazione riceve l'autorità dell'URL di partenza. Il comportamento dei crawler per il 308 è identico al 301: Googlebot segue il redirect e aggiorna l'indice di conseguenza.
Nella pratica la differenza SEO tra 301 e 308 è trascurabile: entrambi trasferiscono valore ed entrambi sono permanenti. La scelta conta solo nel contesto di API e form: se l'applicazione usa richieste POST/PUT/PATCH e il metodo è critico, il 308 è preferibile. Per le normali pagine HTML con richieste GET usa il buon vecchio 301.
Come configurare il redirect 308
Esempi per gli ambienti server più comuni:
# Nginx: permanent redirect with method preservation
server {
listen 80;
server_name example.com;
# All HTTP traffic → HTTPS (308 preserves POST body and is permanent)
return 308 https://example.com$request_uri;
}
# Permanent API endpoint migration
location /api/v1/ {
return 308 https://example.com/api/v2/;
}# Apache (.htaccess)
# Permanent redirect for a single URL with method preservation
Redirect 308 /old-endpoint https://example.com/new-endpoint
# or via mod_rewrite
RewriteEngine On
RewriteRule ^api/v1/(.*)$ https://example.com/api/v2/$1 [R=308,L]// Next.js — permanent redirect with exact 308 status
// Note: permanent: true uses 301 — use middleware for exact 308:
import { NextResponse } from 'next/server';
export function middleware(request) {
if (request.nextUrl.pathname.startsWith('/api/v1/')) {
const newUrl = request.nextUrl.clone();
newUrl.pathname = newUrl.pathname.replace('/api/v1/', '/api/v2/');
return NextResponse.redirect(newUrl, { status: 308 });
}
}<?php
// PHP: explicit 308
http_response_code(308);
header('Location: https://example.com/new-endpoint');
exit();
?># Verify via curl — confirm the response is exactly 308
curl -I -X POST https://example.com/old-endpoint
# HTTP/2 308
# location: https://example.com/new-endpoint