1

O teste que falta antes de publicar um link curto: HEAD, GET e redirecionamentos

Você vai colocar um link curto num QR Code impresso, num e-mail ou numa documentação. Antes de publicar, roda curl -I, vê um Location correto e considera o teste encerrado. Parece razoável. Só que esse comando não reproduz a requisição que acontece quando alguém abre o link no navegador.

-I faz uma requisição HEAD. Ao abrir a URL, o navegador normalmente faz GET. Pela semântica do HTTP, HEAD deve se comportar como GET sem enviar o corpo da resposta. Na prática, uma configuração equivocada pode tratar os dois métodos de formas diferentes. O teste com HEAD continua útil; o problema é usá-lo como prova única.

Montei um laboratório local pequeno para mostrar a diferença, sem depender de nenhum encurtador real.

Primeiro, suba o laboratório

Salve o código abaixo como redirect-lab.mjs e execute node redirect-lab.mjs. Ele usa apenas o módulo HTTP do Node.js. O comportamento inconsistente é proposital: serve para demonstrar por que vale comparar os métodos, não para sugerir que HEAD e GET devam levar a destinos diferentes.

import http from 'node:http';

http.createServer((req, res) => {
  if (req.url === '/curto') {
    res.writeHead(302, {
      Location: req.method === 'HEAD' ? '/pagina-antiga' : '/pagina-nova',
      'Cache-Control': 'no-store',
    });
    res.end();
    return;
  }

  if (req.url === '/pagina-antiga') {
    res.writeHead(404);
    res.end('Página antiga não encontrada\n');
    return;
  }

  if (req.url === '/pagina-nova') {
    res.writeHead(200);
    res.end('Página nova\n');
    return;
  }

  res.writeHead(404);
  res.end();
}).listen(8765, '127.0.0.1');

Primeiro salto não é a viagem inteira

Vamos partir de uma URL de teste:

http://127.0.0.1:8765/curto

Para ver a resposta ao HEAD:

curl -sS -I http://127.0.0.1:8765/curto

Para ver os cabeçalhos de uma requisição GET, sem mostrar o corpo na tela:

curl -sS -D - -o /dev/null http://127.0.0.1:8765/curto

Aqui, -D - imprime os cabeçalhos recebidos e -o /dev/null descarta o corpo da resposta. Diferente de -I, isso ainda é um GET. Sem -L, o curl para na primeira resposta de redirecionamento. O manual do curl documenta essas opções.

Se você quer acompanhar os redirecionamentos HTTP até a resposta final, acrescente -L e um limite de saltos:

curl -sS -L --max-redirs 5 -D - -o /dev/null \
  -w 'final=%{url_effective} saltos=%{num_redirects} codigo=%{http_code}\n' \
  http://127.0.0.1:8765/curto

Assim aparecem os cabeçalhos de cada etapa, seguidos pela URL efetiva, pela quantidade de redirecionamentos seguidos e pelo código da última resposta. O limite impede que um loop faça o teste seguir dezenas de URLs.

O terminal com o laboratório deve continuar aberto. Rode os três comandos em outro terminal. No primeiro, a parte importante da saída é:

HTTP/1.1 302 Found
Location: /pagina-antiga

No GET sem -L, a resposta já muda:

HTTP/1.1 302 Found
Location: /pagina-nova

No GET com -L, o curl segue esse segundo caminho:

HTTP/1.1 302 Found
Location: /pagina-nova

HTTP/1.1 200 OK
final=http://127.0.0.1:8765/pagina-nova saltos=1 codigo=200

Os trechos acima foram executados no laboratório local; omiti data e cabeçalhos não essenciais. Se você tivesse conferido apenas curl -I, teria registrado /pagina-antiga como destino, embora o GET chegue a /pagina-nova.

Como interpretar um teste de verdade

Há três perguntas diferentes, e cada comando responde só a parte delas:

  1. Qual é o primeiro salto? Leia o código 3xx e o cabeçalho Location da primeira resposta. O valor pode ser relativo, como /pagina-nova; nesse caso, ele é resolvido a partir da URL atual.
  2. HEAD e GET concordam? Compare as respostas iniciais. Se não concordarem, investigue a aplicação, o proxy ou a CDN antes de publicar o link. O laboratório acima é um exemplo deliberadamente quebrado.
  3. Onde termina a cadeia HTTP? Use GET com -L e confira cada resposta, a URL efetiva e o código final. Um 200 no fim significa que houve uma resposta bem-sucedida naquele ponto da cadeia HTTP; não prova que a página mostrada ao usuário seja o destino esperado.

O último detalhe importa. Uma página intermediária pode responder 200 e depois navegar por JavaScript ou por meta refresh. O curl não executa JavaScript como um navegador, e -L acompanha redirecionamentos HTTP, não todos os mecanismos de navegação de uma página. A documentação da MDN separa esses tipos de redirecionamento.

Se o resultado do terminal e o do navegador diferirem, abra as ferramentas de desenvolvimento, ative Preserve log na aba Network e observe a sequência real de requisições. Isso ajuda a separar um redirecionamento HTTP de uma navegação iniciada pelo HTML ou pelo JavaScript.

O limite que eu não ignoraria

Esse procedimento não certifica a segurança de uma URL. Ao requisitar um link, você já entra em contato com o servidor, que pode registrar a visita ou contá-la como clique. O destino também pode variar por horário, região, dispositivo ou outros sinais. Para uma URL suspeita, não faça um processo automatizado seguir destinos arbitrários a partir de uma rede interna só porque o primeiro Location parece confiável.

Para links sob seu controle, a regra prática é simples: compare HEAD e GET, siga a cadeia HTTP com um limite e faça uma última verificação no navegador. São testes complementares, não três maneiras de obter a mesma resposta.


Transparência: colaboro com o encurtar.link. O laboratório deste texto é genérico, roda localmente e não descreve a implementação do serviço.

Carregando publicação patrocinada...