Un redirect 301 in .htaccess è una riga:
Redirect 301 /old-page https://example.com/new-page
Salvalo nel file .htaccess nella tua document root ed è attivo immediatamente. Apache legge il file a ogni richiesta, quindi non c'è riavvio né deploy. La direttiva viene da mod_alias, presente praticamente su ogni installazione Apache, e invia un 301 Moved Permanently con un header Location. Questo è tutto il lavoro.
Quasi tutto quello che va storto con i redirect Apache succede dopo questo punto: ricorrere a RewriteRule quando basterebbe Redirect, mescolare i due moduli in un unico file e ottenere un ordine che nessuno si aspettava, o perdere la query string lungo il tragitto. Questo articolo copre le quattro regole che vale la pena memorizzare, la trappola dell'ordine di esecuzione che fa comportare male file che sembrano corretti, e come testare un redirect senza che il tuo browser ti menta. Per il quadro più ampio su dove possono vivere i redirect, vedi come reindirizzare un URL.
La riga singola che copre la maggior parte dei redirect
Redirect prende uno stato, un percorso da far corrispondere e un target. Il target può essere un URL completo o un percorso sullo stesso host:
Redirect 301 /old-page /new-page
Redirect 301 /shop https://shop.example.com/
RedirectMatch 301 ^/blog/([0-9]{4})/(.*)$ /articles/$2
Ci sono due comportamenti che vale la pena conoscere prima di usarlo. Primo, la guida stessa di Apache è esplicita sul fatto che questo è lo strumento giusto: "Questo tipo di semplice redirect di un URL, o di una classe di URL, verso un'altra destinazione, dovrebbe essere realizzato usando queste direttive piuttosto che RewriteRule."
Secondo, e questo sorprende le persone: "Ricorda che Redirect conserva le informazioni sul percorso. Vale a dire, un redirect per un URL /one reindirizzerà anche tutti gli URL sotto di esso, come /one/two.html e /one/three/four.html." Se vuoi solo il percorso esatto, RedirectMatch 301 ^/one$ lo ancora. Altrimenti hai appena reindirizzato un intero sottoalbero, il che a volte è esattamente ciò che volevi e a volte è una mattinata molto confusa.
RedirectMatch è la versione con le espressioni regolari, e copre la maggior parte dei casi per cui le persone aprono mod_rewrite. I gruppi catturati finiscono in $1, $2 e così via, quindi un rinominare una directory o un cambio di schema URL basato su date diventano una riga sola.
Quando serve davvero RewriteRule
Ricorri a mod_rewrite quando la decisione dipende da qualcosa diverso dal percorso. Host, query string, metodo della richiesta, cookie e user agent sono tutti visibili a RewriteCond e invisibili a Redirect:
RewriteEngine On
RewriteCond %{QUERY_STRING} (^|&)ref=oldpartner(&|$)
RewriteRule ^landing$ /partners/oldpartner? [R=301,L]
C'è un'insidia nel contesto per-directory che spiega una grande fetta delle regole copiate e incollate che non fanno assolutamente nulla. Apache rimuove il prefisso della directory prima di far corrispondere, quindi il pattern non vede mai una barra iniziale: "Il prefisso rimosso termina sempre con una barra, il che significa che la corrispondenza avviene contro una stringa che non ha mai una barra iniziale. Pertanto, un Pattern con ^/ non corrisponde mai nel contesto per-directory."
Questo è il motivo per cui RewriteRule ^/old$ /new [R=301] funziona quando qualcuno la incolla in un virtual host e fallisce silenziosamente in .htaccess. Togli la barra: ^old$. Quando la tua sostituzione è un percorso relativo e la rewrite vive in una sottodirectory, potresti anche avere bisogno di RewriteBase per dire ad Apache a cosa sono relativi i percorsi.
La trappola dell'ordine di esecuzione
Questa è quella che costa un pomeriggio intero alle persone. La posizione della riga nel file non decide quale modulo viene eseguito per primo.
Apache lo documenta chiaramente: "Se mescoli Redirect e RewriteRule nello stesso contesto, tieni presente che il loro ordine di esecuzione dipende da dove appaiono. Nel contesto server/virtual-host, mod_rewrite viene eseguito per primo; nel contesto per-directory (.htaccess), mod_alias viene eseguito per primo."
Leggilo due volte, perché la conseguenza è controintuitiva. In un file .htaccess, un Redirect in fondo al file batte un RewriteRule in cima. Sposta le stesse identiche regole in un virtual host e il vincitore si inverte. Nemmeno il flag [L] ti salva: significa ultima regola in questo passaggio di mod_rewrite, non ultima regola nel file, e non ha alcuna autorità su un altro modulo.
La regola pratica che seguo: un modulo per file. Se un progetto ha bisogno di condizioni da qualche parte, fai tutti i suoi redirect con mod_rewrite ed elimina le righe Redirect. I file misti sono l'origine delle segnalazioni di bug del tipo "il redirect funziona in staging ma non in produzione", perché i due ambienti mettono le regole in contesti diversi.
Query string: mantenute, sostituite o eliminate
I link di marketing vivono e muoiono in base alle loro query string, quindi questa tabella vale la pena tenerla a portata di mano. È tutto comportamento documentato, non folklore.
| Cosa scrivi | Query string originale | Note |
|---|---|---|
Redirect 301 /a /b | Trasportata | mod_alias la aggiunge per te |
RedirectMatch 301 ^/a$ /b | Trasportata | Stesso modulo, stesso comportamento |
RewriteRule ^a$ /b [R=301] | Passa inalterata | Il comportamento predefinito documentato |
RewriteRule ^a$ /b?src=x [R=301] | Sostituita dalla tua | I tuoi parametri vincono |
RewriteRule ^a$ /b?src=x [R=301,QSA] | Combinata con la tua | QSA aggiunge quella originale |
RewriteRule ^a$ /b? [R=301] | Eliminata | Un ? nudo la azzera |
La formulazione di Apache sul comportamento predefinito: "Per impostazione predefinita, la query string viene passata inalterata." E sui flag, [QSA] "aggiunge qualsiasi query string dall'URL della richiesta originale a qualsiasi query string creata nel target della rewrite", mentre [QSD] scarta quella in arrivo. Se reindirizzi verso un URI assoluto, la query string viene trasportata a meno che tu non richieda [QSD].
Il fallimento che questo previene è silenzioso e costoso. Una regola che sostituisce la query string elimina utm_source e utm_campaign lungo il tragitto, il tuo strumento di analisi attribuisce la sessione al traffico diretto, e nulla genera errori. Nessuno se ne accorge finché qualcuno non chiede perché la campagna di primavera non ha ricevuto alcun merito. Parametri UTM che non compaiono in GA4 copre la diagnosi dal lato dell'analisi.
Se ti ritrovi a mantenere decine di redirect di campagna in un file di configurazione del server, è un segnale piuttosto che una scocciatura. Le regole sul server richiedono un deploy, una revisione della configurazione Apache e qualcuno con accesso shell. Sposta i link di campagna su link brevi che puoi modificare tu stesso e tieni .htaccess per i redirect strutturali in cui è bravo.
HTTPS e www in un salto, non due
Lo snippet più copiato su internet fa questo in due blocchi di regole, il che significa che un visitatore che arriva su http://example.com/page viene reindirizzato due volte: una per aggiungere TLS, una per aggiungere www. Due salti, due round trip, e un segnale leggermente più debole a ogni passaggio.
Una regola, due condizioni, un salto:
RewriteEngine On
RewriteCond %{HTTPS} !=on [OR]
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L]
Dietro una CDN o un load balancer, %{HTTPS} è di solito off all'origine anche quando il visitatore è su HTTPS, perché il TLS termina upstream. Testa invece %{HTTP:X-Forwarded-Proto}:
RewriteCond %{HTTP:X-Forwarded-Proto} !https
Sbaglia questo e costruisci un loop di redirect infinito: il proxy invia HTTPS, l'origine pensa che sia HTTP, reindirizza verso HTTPS, e il giro continua finché il browser non si arrende. Come risolvere un loop di redirect illustra come diagnosticarlo dagli header della risposta.
Perché non funziona
Nell'ordine in cui le controllo:
AllowOverrideèNone. La documentazione di Apache afferma il comportamento predefinito: "Questo significa che i file.htaccessvengono completamente ignorati a meno che tu non li abiliti esplicitamente per una directory." Testalo mettendo spazzatura deliberata sulla prima riga. Nessun errore 500 significa che il tuo file non viene letto affatto, e ogni regola al suo interno è pura decorazione.- Il file è nel posto sbagliato o ha un nome sbagliato. Deve essere
.htaccess, con il punto iniziale, nella directory a cui la richiesta corrisponde. Gli editor che salvano gentilmentehtaccess.txtsono una causa ricorrente. - mod_rewrite non è caricato.
Redirectfunziona,RewriteRulesilenziosamente no, il che manda le persone a fissare la propria regex per un'ora. - Il tuo browser ha memorizzato nella cache il vecchio 301. Sia Chrome che Firefox mettono in cache i redirect permanenti in modo aggressivo, per profilo del browser, quindi il fix che hai appena distribuito è invisibile a te e funziona benissimo per tutti gli altri. Durante lo sviluppo, usa
R=302e passa aR=301una volta che la regola è corretta. - La regola corrisponde al proprio stesso target.
RewriteRule ^(.*)$ /index.php/$1senza una guardia è il classico. Aggiungi una condizione che esenta la destinazione.
Testa con curl, non con il browser
Un solo comando ti dice lo stato, il target e quanti salti ha fatto:
curl -sIL https://example.com/old-page | grep -iE '^HTTP|^location'
Leggi l'output come una sequenza. Due righe HTTP/2 301 prima del 200 significano due salti, e ogni salto è un round trip reale per un visitatore reale su una rete mobile. La documentazione di Google sui redirect tratta un redirect permanente come il segnale più forte per consolidare un URL, e arrivarci in un passaggio è strettamente meglio che arrivarci in tre. Il nostro link checker mostra la stessa catena in un browser, e 301 contro 302 redirect copre quale stato inviare quando non sei sicuro.
Testa i percorsi che contano piuttosto che quello che hai appena scritto: la radice, un percorso profondo, un percorso con una query string e il target stesso. Quest'ultimo intercetta i loop prima dei tuoi visitatori.
Quando non usare affatto .htaccess
La posizione stessa di Apache è inequivocabile. "Se hai accesso al file di configurazione principale del server, dovresti metterci tutta la tua configurazione invece che nei file .htaccess," perché l'analisi a ogni richiesta costa lavoro reale: "consentire i file .htaccess causa un calo di prestazioni, che tu li usi effettivamente o no." Sull'hosting condiviso non hai scelta. Su un server che controlli, la configurazione principale è la sede migliore per qualsiasi cosa strutturale.
C'è un secondo motivo per tenere le regole completamente fuori dal file, e non ha nulla a che fare con le prestazioni. I redirect che appaiono su carta, in un QR code, o sulla presentazione di qualcun altro devono sopravvivere al tuo server web, alla migrazione del tuo CMS, e possibilmente al tuo provider di hosting. Una regola in .htaccess è a un deploy sconsiderato di distanza dallo sparire, e nessuno segnala un link stampato morto finché la campagna non è finita. I redirect strutturali appartengono al server; i link di campagna e stampati appartengono a un posto che puoi modificare in pochi secondi e misurare senza fare grep sui log di accesso.
Leggi la serie cornerstone
Questo articolo fa parte del cluster tutorial. Per la mappa completa, tipi di redirect copre ogni codice di stato e metodo lato client, e come reindirizzare un URL copre i sei posti in cui può vivere un redirect.
Correlati nel blog
Domande frequenti
Come si crea un redirect 301 in .htaccess?
Metti una riga nel file .htaccess nella tua document root: Redirect 301 /old-page https://example.com/new-page. Apache legge .htaccess a ogni richiesta, quindi il redirect è attivo nel momento in cui salvi il file. Nessun riavvio, nessun deploy. Quella direttiva viene da mod_alias, che è abilitato praticamente su ogni installazione Apache.
Qual è la differenza tra Redirect e RewriteRule?
Redirect e RedirectMatch vengono da mod_alias e fanno una cosa sola: inviano un codice di stato e un header Location. RewriteRule viene da mod_rewrite e può ispezionare l'host, la query string, i cookie o lo user agent prima di decidere. La documentazione stessa di Apache dice che i redirect semplici dovrebbero usare mod_alias invece di RewriteRule, e tratta mod_rewrite come ultima risorsa.
Perché il mio redirect in .htaccess non funziona?
Cinque cause coprono quasi tutti i casi: AllowOverride è impostato su None quindi il file viene ignorato del tutto, il file non è nella document root o ha un nome sbagliato, mod_rewrite non è caricato, il tuo browser ha memorizzato nella cache un 301 precedente e non chiede più nulla al server, oppure la regola corrisponde al proprio stesso target e crea un loop. Testa con curl invece che con un browser, perché un 301 in cache fa sembrare rotta una regola che invece è corretta.
La query string sopravvive a un redirect 301 in .htaccess?
Con Redirect e RedirectMatch sì, viene trasportata automaticamente. Con RewriteRule la risposta dipende dalla sostituzione: nessun punto interrogativo in essa e la query string originale passa inalterata, un punto interrogativo con i tuoi parametri la sostituisce, un punto interrogativo nudo alla fine la elimina, e il flag QSA combina entrambe. Sbagliare questo punto elimina silenziosamente i parametri UTM.
Come reindirizzo HTTP verso HTTPS e non-www verso www in un solo salto?
Usa una sola regola con due condizioni unite da OR, riscrivendo verso lo schema e l'host canonici in un unico passaggio. Due blocchi di regole separati producono due redirect per chiunque arrivi su http:// senza www, e ogni salto extra costa latenza e diluisce il segnale. Dietro un proxy o una CDN, testa %{HTTP:X-Forwarded-Proto} invece di %{HTTPS}, altrimenti costruirai un loop.
.htaccess rallenta un sito?
Leggermente, e inevitabilmente. La documentazione di Apache è schietta al riguardo: consentire i file .htaccess causa un calo di prestazioni che tu li usi o no, perché httpd cerca il file in ogni directory a ogni richiesta. Se hai accesso alla configurazione principale del server, le stesse regole appartengono lì, caricate una sola volta all'avvio.
Prova Elido
Incolla un URL, ottieni un link breve
Senza registrazione. Il link vive 30 giorni. Iscriviti per conservarlo.
Gratis, nessuna registrazione richiesta · 2 al giorno