A descrição do próprio Chromium é admiralvemente simples: “A tentativa de carregar uma URL resultou em muitos redirecionamentos.” O navegador seguiu uma cadeia de redirecionamentos, a cadeia não terminou e em algum ponto parou de seguir.

O número em que para vem do Fetch Standard, que é inequívoco sobre isso: se o redirect count da requisição é 20, então retorna um erro de rede. Portanto, vinte saltos, e depois a página que você vê é do navegador, não sua.

O que torna esse erro digno de seu próprio artigo não é o mecanismo, que é óbvio. É que um loop de redirecionamento quase nunca é uma única coisa quebrada. São duas coisas, cada uma se comportando exatamente como configurado, discordando sobre algo que nenhuma delas consegue ver.

O clássico, que é uma discordância sobre HTTPS

Você coloca um CDN ou um balanceador de carga na frente de seu aplicativo. Ele encerra TLS, que é seu trabalho, e encaminha a requisição para seu origin por HTTP simples, que é normal e geralmente deliberado.

Seu aplicativo tem uma regra que diz: se essa requisição não for HTTPS, redirecione-a para HTTPS. Também correto, e em um servidor sem proxy na frente, exatamente certo.

Agora junte-os. O navegador pede https://example.com. O CDN encerra TLS e encaminha http://example.com para seu app. Seu app vê HTTP simples, faz a coisa sensata e responde “redirecione para https://example.com”. O navegador obedece. O CDN encerra TLS e encaminha HTTP. Vinte vezes, e depois o navegador desiste.

Nenhum componente está mal configurado por si só. O aplicativo está forçando HTTPS. O proxy está encerrando TLS. O bug vive na lacuna entre eles, por isso ambas as equipes podem olhar para sua própria configuração e concluir corretamente que está bem.

A solução é que o app tem que parar de fazer a pergunta errada. Em vez de “essa requisição foi HTTPS”, ele precisa perguntar “a requisição original foi HTTPS”, que é para o que o cabeçalho X-Forwarded-Proto existe. A maioria dos frameworks tem uma configuração para confiar nesse cabeçalho de um proxy conhecido, e geralmente está desativada por padrão por uma boa razão: um cabeçalho que qualquer um pode definir não é evidência a menos que você saiba quem o definiu.

A mesma forma, três vezes mais

Uma vez que você vê o padrão, os outros loops comuns têm a mesma história com nomes diferentes.

www contra o apex. Uma camada redireciona example.com para www.example.com. Outra, adicionada depois ou por outra pessoa, redireciona www de volta ao apex. Cada regra é defensável. O par é um loop.

A barra à direita. Seu servidor web redireciona /about para /about/. O roteador do seu framework redireciona /about/ para /about. Ambos estão forçando uma forma canônica. Discordam sobre qual é a canônica.

O login loop, que é o que chega aos usuários reais. O app não vê uma sessão válida, então redireciona para /login. A página de login verifica o cookie de sessão, acredita que está conectado e redireciona para o app. Volta e volta.

Vale a pena refletir sobre esse último, porque a causa geralmente é o cookie não persistir em vez das regras de redirecionamento estarem erradas: um cookie Secure em uma página servida por HTTP, um cookie SameSite=None sem Secure, um cookie definido em www.example.com sendo lido em example.com, ou um navegador configurado para recusar cookies de terceiros em um contexto incorporado. A lógica de redirecionamento está correta por toda parte. Ela está agindo sobre uma sessão que nunca persistiu.

Fraco
"Sua página de login está presa em um loop. Ela só fica recarregando."
Melhor
ERR_TOO_MANY_REDIRECTS em /login, apenas em uma janela privada, apenas depois que faço logout e login novamente. Funciona minha janela normal. Cadeia é /app → /login → /app.

Por que esse é inusualmente difícil de ver de dentro

Um loop de redirecionamento é geralmente específico para um estado em que você não está.

Se for o login loop, seu cookie já está definido e funcionando, então o site se comporta perfeitamente para você e faz loop para qualquer um que chegue novo. Se for uma regra www que alguém adicionou semana passada, faz loop apenas para pessoas que digitaram o outro nome de domínio. Se depender de um cookie que o navegador está recusando, reproduz em uma janela privada e em nenhum outro lugar.

E a verificação óbvia erra. curl -I https://example.com mostra uma resposta, que será um 301 perfeitamente razoável com um cabeçalho Location. Nada sobre isso diz que a cadeia nunca termina. O que você quer é seguir o todo:

curl -sIL -o /dev/null -w '%{url_effective} %{http_code}\n' https://example.com
curl -sI https://example.com | grep -i '^location'

Ou abra a guia Rede com Preservar registro marcado, que é a única maneira de manter os saltos anteriores em vez de limpá-los a cada navegação. A cadeia é o diagnóstico: leia o cabeçalho Location a cada passo e você geralmente pode ver as duas regras argumentando dentro de três saltos.

Session Replay

Extensão gratuita do Chrome. Um clique na página que está se comportando mal captura a screenshot, o console e o log de rede, e oferece a você um link para colar no ticket.

Obtenha a extensão

Uma coisa sobre 301 que vale a pena saber antes de usá-lo

Um 301 não é simplesmente um 302 que significa mais.

O MDN é específico sobre uma consequência que surpreende as pessoas: no Fetch Standard, um user agent recebendo um 301 em resposta a um POST usa GET para a requisição redirecionada. Seu envio de formulário se torna um GET, o corpo desaparece e a falha não se parece nada com um problema de redirecionamento. Se você precisar que o método seja preservado, 308 é o que proíbe mudá-lo.

A regra geral é mais chata e mais útil: use 302 ou 307 enquanto ainda está descobrindo qual é a URL canônica, e use 301 ou 308 quando tiver certeza. Um redirecionamento permanente é uma afirmação, e afirmações são muito mais fáceis de fazer do que retirar.

O que levar disso

ERR_TOO_MANY_REDIRECTS significa vinte saltos sem um fim, e o fim está faltando porque duas regras discordam, não porque uma está quebrada.

Então não comece procurando pela regra quebrada. Comece listando cada camada que tem permissão para emitir um redirecionamento: o CDN, o balanceador de carga, o servidor web, o framework, o aplicativo e tudo o que um plugin adicionou sem avisar a ninguém. Depois leia a cadeia, um cabeçalho Location de cada vez, e encontre os dois que estão argumentando.

E quando não se reproduz para você, isso é informação em vez de um obstáculo. Significa que o loop depende de um estado que você já passou, e a forma mais rápida para ele é uma janela privada, um nome de domínio diferente, ou a visão completa do que o navegador realmente recebeu de alguém para quem está falhando agora.