Cadeia de redirect: como encontrar os saltos e apontar o link antigo direto ao destino
Descubra quantos saltos existem entre um link antigo e a página atual com curl, achate o mapa de redirecionamentos com um script e configure o nginx para responder em um salto só.
O artigo sobre instalação do Node.js mudou de endereço duas vezes em três anos. Um link antigo, num fórum, aponta para http://oficinadocodigo.com.br/blog/como-instalar-node. Até chegar à página atual, o visitante passa por quatro redirecionamentos: HTTP para HTTPS, apex para www, slug antigo para o intermediário e intermediário para o atual. No navegador parece um clique só, um pouco lento. A resposta curta: todo endereço antigo deve redirecionar direto para o destino final, em um salto. Descubra os saltos com curl -sIL, achate o mapa para que cada origem aponte para a página atual e faça os blocos que trocam protocolo e host já mandarem para o destino final.
Este guia mostra o diagnóstico, um script que achata o mapa de redirecionamentos e detecta loops, e a configuração do nginx que responde tudo em um salto.
Por que as cadeias aparecem
Ninguém cria uma cadeia de propósito. Ela se forma em camadas. Primeiro alguém configura HTTP para HTTPS. Depois, outra pessoa configura o host canônico, e o redirecionamento de host roda depois do de protocolo. Depois o slug do artigo muda, e o redirecionamento novo aponta para o endereço vigente na época. Na segunda mudança, alguém cria uma regra do intermediário para o novo, sem atualizar a primeira.
Cada camada, sozinha, está certa. Juntas, formam uma fila. E a fila cresce a cada reorganização, porque a regra mais fácil de escrever é sempre "do endereço que era atual até ontem para o de hoje".
O que cada salto custa
Cada redirecionamento é uma ida e volta inteira: o navegador recebe o 301, lê o Location, abre ou reaproveita uma conexão e pede de novo. Mudar de host pode exigir nova consulta de DNS e novo handshake TLS. No celular, com rede ruim, quatro saltos podem somar um tempo que a pessoa percebe antes de ver qualquer coisa.
Para a busca, o robô do Google segue redirecionamentos, mas até um número limitado de saltos (a documentação fala em até 10), e recomenda apontar direto para o destino. Cada salto também é uma chance de algo se perder: a query string que uma regra mal escrita descarta, o HTTPS que uma regra antiga troca por HTTP, uma página intermediária que alguém apagou e agora dá 404.
E há o loop: A redireciona para B, que redireciona para A. O navegador desiste com "muitos redirecionamentos", e a página fica inacessível para todo mundo que chega por aquele caminho.
Como diagnosticar com curl
O navegador esconde os saltos intermediários. O curl mostra todos. Com -I ele pede só os cabeçalhos, com -L segue os redirecionamentos:
$ curl -sIL http://oficinadocodigo.com.br/blog/como-instalar-node | grep -iE '^(HTTP|location)'
HTTP/1.1 301 Moved Permanently
Location: https://oficinadocodigo.com.br/blog/como-instalar-node
HTTP/2 301
location: https://www.oficinadocodigo.com.br/blog/como-instalar-node
HTTP/2 301
location: https://www.oficinadocodigo.com.br/blog/instalar-node
HTTP/2 301
location: https://www.oficinadocodigo.com.br/blog/instalar-nodejs-no-linux
HTTP/2 200
Quatro saltos. Para contar rápido numa lista de endereços, o -w imprime o número de redirecionamentos e o destino final:
$ curl -s -o /dev/null -L -w '%{num_redirects} %{url_effective}\n' http://oficinadocodigo.com.br/blog/como-instalar-node
4 https://www.oficinadocodigo.com.br/blog/instalar-nodejs-no-linux
Um detalhe: -I envia um pedido HEAD, e algumas aplicações respondem diferente a HEAD e a GET. Se o resultado parecer estranho, a segunda forma, sem -I, usa GET e descarta o corpo.
Rode isso para os endereços que importam: os mais antigos que ainda recebem tráfego, os que aparecem em links externos e os que estavam no sitemap anterior.
Como achatar o mapa de redirecionamentos
- Junte todas as regras de slug num lugar só. Um arquivo de mapa, uma tabela no banco, o que você usa. Regras espalhadas em vários arquivos são onde as cadeias se escondem.
- Resolva cada origem até o destino final. Siga a cadeia dentro do próprio mapa e grave o destino último, não o próximo.
- Detecte loops. Se uma origem volta a si mesma, pare e corrija à mão.
- Faça os redirecionamentos de protocolo e host já mandarem para o destino final. Quem chega por HTTP com slug antigo deve ir direto para o HTTPS, no host certo, com o slug atual.
- Atualize links internos, sitemap e canonical. Seu próprio site nunca deve apontar para um endereço que redireciona.
- Repita o diagnóstico. Todo endereço antigo deve mostrar
1nonum_redirects.
O script que achata e acusa loop
Na Oficina do Código, o mapa de slugs virou um script Node.js que gera o arquivo incluído pelo nginx:
// achatar-redirects.js
const redirects = new Map([
['/blog/como-instalar-node', '/blog/instalar-node'],
['/blog/instalar-node', '/blog/instalar-nodejs-no-linux'],
['/blog/node-no-ubuntu', '/blog/como-instalar-node'],
]);
function destinoFinal(origem) {
const visitados = new Set([origem]);
let atual = redirects.get(origem);
while (redirects.has(atual)) {
if (visitados.has(atual)) {
throw new Error('Loop de redirect a partir de ' + origem);
}
visitados.add(atual);
atual = redirects.get(atual);
}
return atual;
}
for (const origem of redirects.keys()) {
console.log(' ' + origem + ' ' + destinoFinal(origem) + ';');
}
Rodando com node achatar-redirects.js > /etc/nginx/redirects.map, a saída é:
/blog/como-instalar-node /blog/instalar-nodejs-no-linux;
/blog/instalar-node /blog/instalar-nodejs-no-linux;
/blog/node-no-ubuntu /blog/instalar-nodejs-no-linux;
Repare na terceira linha: node-no-ubuntu apontava para um endereço que já redirecionava duas vezes. Agora vai direto.
O nginx respondendo em um salto
O map fica no contexto http, fora dos blocos server. A mesma verificação entra nos blocos que só trocam protocolo e host, para que o link antigo por HTTP também chegue em um salto:
map $uri $destino_novo {
default "";
include /etc/nginx/redirects.map;
}
server {
listen 80;
server_name oficinadocodigo.com.br www.oficinadocodigo.com.br;
if ($destino_novo) {
return 301 https://www.oficinadocodigo.com.br$destino_novo$is_args$args;
}
return 301 https://www.oficinadocodigo.com.br$request_uri;
}
server {
listen 443 ssl;
server_name www.oficinadocodigo.com.br;
# ssl_certificate ... (como no restante da configuração)
if ($destino_novo) {
return 301 https://www.oficinadocodigo.com.br$destino_novo$is_args$args;
}
# ... site
}
O bloco HTTPS do apex, que redireciona para o www, recebe a mesma verificação. O $is_args$args devolve a query string original. Depois de sudo nginx -t e do reload, o mesmo curl do começo mostra 1 https://www.oficinadocodigo.com.br/blog/instalar-nodejs-no-linux. A escolha do host canônico e a configuração completa de cada bloco estão em com www ou sem www, e a escolha entre 301, 302, 307 e 308 em redirecionar URL do jeito certo.
Erros comuns
- Testar só no navegador. Ele esconde os saltos e ainda guarda 301 em cache, mostrando um comportamento que o servidor já não tem.
- Criar a regra nova apontando para o slug anterior. É assim que a cadeia nasce; cada regra deve apontar para o destino atual.
- Deixar protocolo e host fora da conta. O mapa de slugs fica perfeito e a cadeia continua com dois saltos antes dele.
- Perder a query string. Parâmetros de campanha e filtros somem no meio do caminho e a página final abre errada.
- Apagar redirecionamentos antigos cedo demais. Links externos e favoritos continuam existindo por anos e passam a dar 404.
- Links internos apontando para endereços antigos. Seu próprio site obriga cada visitante a passar pelo redirecionamento.
Checklist
- As regras de slug estão num único arquivo ou tabela.
- Cada origem aponta para o destino final, não para o próximo salto.
- O script de achatamento roda sem acusar loop.
- Os blocos de protocolo e host consultam o mesmo mapa.
- A query string chega intacta ao destino.
- Links internos, sitemap e canonical não apontam para endereços que redirecionam.
- O
num_redirectsdos endereços antigos mais acessados é 1.
Pegue o link mais antigo do seu site que você encontrar num fórum ou num e-mail velho e rode o curl com num_redirects. Quantos saltos existem entre ele e a página de hoje?
Referência: https://developers.google.com/search/docs/crawling-indexing/301-redirects