
La descrizione stessa di Chromium è ammirabilmente lineare: “Il tentativo di caricare un URL ha risultato in troppi redirect.” Il browser ha seguito una catena di redirect, la catena non si è conclusa, e a un certo punto ha smesso di seguire.
Il numero in cui si ferma viene dal Fetch Standard, che è inequivocabile: se il conteggio di redirect della richiesta è 20, restituire un errore di rete. Quindi venti hop, e poi la pagina che vedi è quella del browser, non la tua.
Quello che rende questo errore degno del suo articolo non è il meccanismo, che è ovvio. È che un ciclo di redirect non è quasi mai una cosa rotta. Sono due cose, ciascuna che si comporta esattamente come configurata, in disaccordo su qualcosa che nessuna delle due riesce a vedere.
Il caso classico, che è un disaccordo su HTTPS
Metti un CDN o un load balancer di fronte alla tua applicazione. Termina TLS, che è il suo lavoro, e inolttra la richiesta alla tua origin su HTTP semplice, che è normale e di solito deliberato.
La tua applicazione ha una regola che dice: se questa richiesta non è HTTPS, reindirizzala a HTTPS. Anche questo è corretto, e su un server senza proxy di fronte, esattamente giusto.
Ora mettili insieme. Il browser chiede https://example.com. Il CDN termina TLS e inolttra
http://example.com alla tua app. La tua app vede HTTP semplice, fa la cosa sensata, e risponde
“reindirizza a https://example.com”. Il browser obbedisce. Il CDN termina TLS e inolttra HTTP.
Venti volte, e poi il browser si arrende.
Nessun componente è configurato male di per sé. L’applicazione sta forzando HTTPS. Il proxy sta terminando TLS. Il bug vive nello spazio tra loro, ecco perché entrambi i team possono guardare la loro configurazione e concludere correttamente che è a posto.
La correzione è che l’app deve smettere di fare la domanda sbagliata. Invece di “questa richiesta
era HTTPS”, deve chiedere “era HTTPS la richiesta originale”, che è quello che l’header
X-Forwarded-Proto serve a dirle. La maggior parte dei framework ha un’impostazione per fidarsi
di quell’header da un proxy noto, e di solito è disattivata per una buona ragione: un header che
chiunque può impostare non è una prova a meno che tu non sappia chi l’ha impostato.
La stessa forma, altre tre volte
Una volta visto il modello, gli altri cicli comuni sono la stessa storia con sostantivi diversi.
www contro l’apex. Un livello reindirizza example.com a www.example.com. Un altro,
aggiunto più tardi o da qualcun altro, reindirizza www di nuovo all’apex. Ogni regola è
difendibile. La coppia è un ciclo.
La barra finale. Il tuo web server reindirizza /about a /about/. Il router del tuo
framework reindirizza /about/ a /about. Entrambi stanno forzando una forma canonica.
Dissentono su quale sia quella canonica.
Il ciclo di login, che è quello che raggiunge gli utenti veri. L’app non vede una sessione
valida, così reindirizza a /login. La pagina di login controlla il cookie di sessione, crede
di essere collegato, e reindirizza all’app. Avanti e indietro.
Quest’ultimo vale la pena soffermarsi, perché la causa di solito è il cookie che non riesce a
stare piuttosto che le regole di redirect essere sbagliate: un cookie Secure su una pagina
servita su HTTP, un cookie SameSite=None senza Secure, un cookie impostato su
www.example.com che viene letto su example.com, o un browser configurato per rifiutare i
cookie di terze parti in un contesto incorporato. La logica di redirect è corretta in tutto.
Sta agendo su una sessione che non ha mai persistito.
- Debole
- "La tua pagina di login è bloccata in un ciclo. Si ricarica continuamente."
- Migliore
- ERR_TOO_MANY_REDIRECTS su /login, solo in una finestra privata, solo dopo aver fatto logout e nuovo login. Funziona nella mia finestra normale. Catena è /app → /login → /app.
Perché questo è insolitamente difficile da vedere dall’interno
Un ciclo di redirect è spesso specifico per uno stato in cui non sei.
Se è il ciclo di login, il tuo cookie è già impostato e funzionante, così il sito si comporta perfettamente per te e cicla per chiunque arrivi da capo. Se è una regola www che qualcuno ha aggiunto la scorsa settimana, cicla solo per le persone che hanno scritto l’altro nome host. Se dipende da un cookie che il browser sta rifiutando, riproduce in una finestra privata e da nessun’altra parte.
E il controllo ovvio se lo perde. curl -I https://example.com ti mostra una risposta, che sarà
un 301 perfettamente ragionevole con un header Location. Nulla in esso dice che la catena
non termina mai. Quello che vuoi è seguire l’intera cosa:
curl -sIL -o /dev/null -w '%{url_effective} %{http_code}\n' https://example.com
curl -sI https://example.com | grep -i '^location'
Oppure apri la scheda Rete
con Conserva log selezionato, che è l’unico modo per mantenere gli hop precedenti invece di
pulirli ad ogni navigazione. La catena è la diagnosi: leggi l’header Location ad ogni passaggio
e solitamente puoi vedere le due regole in disaccordo entro tre hop.
Session Replay
Estensione Chrome gratuita. Un clic sulla pagina che si comporta male acquisisce lo screenshot, la console e il log di rete, e ti consegna un link da incollare nel ticket.
Una cosa su 301 che vale la pena sapere prima di usarlo
Un 301 non è semplicemente un 302 che lo significa di più.
MDN è specifico su una conseguenza che sorprende le persone: nel Fetch Standard, un user agent
che riceve un 301 in risposta a un POST usa GET per la richiesta reindirizzata. Il tuo
invio di form diventa un GET, il corpo è sparito, e l’errore non assomiglia affatto a un problema
di redirect. Se hai bisogno che il metodo sia preservato, 308 è quello che proibisce di
cambiarlo.
La regola generale è più noiosa e più utile: ricorri a 302 o 307 mentre stai ancora
lavorando per capire quale sia l’URL canonico, e usa 301 o 308 quando ne sei sicuro. Un
redirect permanente è un’affermazione, e le affermazioni sono molto più facili da fare che da
ritirare.
Cosa portare da tutto ciò
ERR_TOO_MANY_REDIRECTS significa venti hop senza una conclusione, e la conclusione manca
perché due regole dissentono, non perché una è rotta.
Quindi non iniziare cercando la regola rotta. Inizia elencando ogni livello che è autorizzato a
emettere un redirect: il CDN, il load balancer, il web server, il framework, l’applicazione, e
qualunque cosa un plugin abbia aggiunto senza dire a nessuno. Poi leggi la catena, uno header
Location alla volta, e trova i due che stanno discutendo.
E quando non riproduce per te, questa è un’informazione piuttosto che un ostacolo. Significa che il ciclo dipende da uno stato che hai già superato, e il modo più veloce per arrivarci è una finestra privata, un nome host diverso, o l’immagine completa di quello che il browser effettivamente ha ricevuto da qualcuno per cui sta fallendo adesso.