O erro aparece assim. Uma integração envia um POST para o seu endpoint. O endpoint funciona, a rota existe, tudo confere quando testado à mão. Mas nos logs aparece um GET numa rota que só aceita POST, respondido com 404 ou 405.
A causa é quase sempre a mesma: entre o cliente e o endpoint há um redirecionamento 301 ou 302. E esses códigos não obrigam o cliente a preservar o método.
Dá para confirmar em dez segundos:
curl -sS -o /dev/null -L -d 'test=1' \
-w 'método após o redirecionamento: %{method}\n' \
'https://httpbingo.org/redirect-to?url=/anything&status_code=301'
Saída: método após o redirecionamento: GET. O corpo da requisição se perde junto.
Troque 301 por 308 no mesmo comando e você obtém POST. A única diferença é o código de status.
Cinco códigos, duas propriedades
Redirecionamentos se distinguem por dois eixos independentes: se são permanentes ou temporários, e se o método da requisição sobrevive.
| Código | Nome | Permanência | Preserva o método |
|---|---|---|---|
| 301 | Moved Permanently | permanente | não |
| 302 | Found | temporário | não |
| 303 | See Other | — | não, sempre GET |
| 307 | Temporary Redirect | temporário | sim |
| 308 | Permanent Redirect | permanente | sim |
Repare na simetria: 307 é um 302 com garantia de método, e 308 é um 301 com garantia de método.
De onde veio essa confusão
Formalmente, a especificação nunca exigiu trocar o método em 301 e 302. Mas os primeiros navegadores e clientes faziam exatamente isso e, quando o descompasso foi notado, a web inteira já funcionava assim.
Então o comportamento foi codificado como permitido: a RFC 9110, especificação vigente da semântica HTTP, permite ao cliente trocar POST por GET em 301 e 302. Permite, mas não exige — o que deixa o comportamento a critério do cliente e torna impossível confiar nele.
Para oferecer uma opção inequívoca, foram introduzidos o 307 e o 308. Neles, trocar o método é proibido: o cliente deve repetir a requisição com o mesmo método e o mesmo corpo. O código 308 está definido na própria RFC 7538, com descrição de referência na documentação da MDN.
Conclusão prática: 301 e 302 só são seguros onde a requisição é com certeza um GET. Onde puder chegar um POST, são necessários 307 ou 308.
A segunda armadilha: redirecionamentos permanentes são cacheados
Essa é esquecida com mais frequência do que o problema do método.
301 e 308 declaram a mudança como permanente, e o navegador tem o direito de cacheá-los por muito tempo — às vezes até o usuário limpar o cache. Depois disso o servidor simplesmente não é consultado.
Daí a regra: um 301 equivocado é quase impossível de reverter. Você corrige a configuração, mas os visitantes que já receberam a resposta antiga continuarão sendo redirecionados. Com 302 e 307 isso não acontece: eles são temporários por definição.
Conselho prático: enquanto o esquema de mudanças não estiver assentado, use códigos temporários. Promover um 302 a 301 depois é fácil; o caminho inverso, não.
O que escolher
A página mudou definitivamente e só aceita GET → 301. O caso clássico: a URL antiga de um artigo, uma mudança na estrutura de endereços.
O mesmo, mas o endpoint aceita POST → 308. Entram aqui APIs, webhooks e formulários.
O destino muda temporariamente, só GET → 302.
Temporário, e o método precisa ser preservado → 307.
Depois de um POST, mandar o usuário para uma página de resultado → 303. É o padrão POST/Redirect/GET: ele transforma deliberadamente a requisição em GET para que recarregar a página não reenvie o formulário. Aqui a troca de método é o objetivo, não um defeito.
Onde isso quebra na prática
Redirecionamento http→https na frente de uma API. O caso mais comum e mais incômodo. O cliente está configurado com http://, o servidor responde 301 apontando para https://, o método se perde. Sintoma: GET nos logs numa rota POST. Resolve-se trocando 301 por 308.
Canonização de host. O redirecionamento de www para sem www (ou o contrário) costuma ser montado como 301. Tudo bem para páginas, mas se uma API mora no mesmo host, vale exatamente o mesmo problema.
Envio de formulários. Um formulário é enviado para um endereço que redireciona. O usuário vê que «não aconteceu nada» porque os dados nunca chegaram ao handler.
Webhooks. Um serviço externo envia um POST para um endereço que você forneceu certa vez. Se esse endereço mudou atrás de um 301, os webhooks param de funcionar silenciosamente enquanto o remetente registra uma resposta bem-sucedida ao redirecionamento.
Os quatro compartilham uma assinatura: o endpoint está saudável, mas a requisição não chega até ele na forma original. Por isso o diagnóstico vai para o lado errado — procura-se o defeito no handler, e ele está na configuração do servidor web.
Por que os encurtadores usam 302
Um link curto quase sempre devolve 302, e essa é uma escolha deliberada, não descuido.
O motivo é a permanência, não o método: o destino de um link curto pode mudar. Usar 301 permitiria aos navegadores cachear o salto para sempre, e depois de trocar o destino parte dos visitantes continuaria caindo no endereço antigo. O método aqui é irrelevante: links curtos são seguidos com requisições GET.
O mecanismo está tratado à parte em como funcionam os encurtadores de links.
O que a escolha do código não muda
Dois equívocos bastante difundidos.
A autoridade do link. Escolher entre 301 e 302 não afeta a transmissão de autoridade — o Google confirmou isso ainda em 2016. O tratamento completo está em os links encurtados transmitem autoridade?.
A escolha da URL canônica. Um redirecionamento e o rel="canonical" resolvem problemas diferentes: o redirecionamento retira um endereço de circulação, o canonical deixa os dois acessíveis e aponta o principal. Quando usar cada um está descrito no guia de canonical.
Checklist curto
- Em rotas que aceitam
POST, usar 307 ou 308, não 302 nem 301. - Verificar o redirecionamento http→https à parte: costuma ser posto por uma regra geral e a API é esquecida.
- Enquanto o esquema não estiver assentado, códigos temporários. 301 e 308 são cacheados e quase irreversíveis.
- Depois de processar um formulário, usar 303: é o comportamento correto, não um erro.
- Reduzir cadeias a um único salto: cada salto extra acrescenta latência e risco.