Código de status HTTP · Redirecionamento (3xx)
308 Permanent Redirect
O status 308 Permanent Redirect significa que o recurso mudou de vez para a URL do Location e o cliente deve repetir o pedido lá com o mesmo método e corpo. É a versão permanente do 307 e a escolha segura para mudar endpoints de API ou qualquer URL que receba POST.
| Classe | 3xx, Redirecionamento |
|---|---|
| Definido em | RFC 9110 §15.4.9 |
| Pode ir para o cache por padrão | Sim, de forma heurística |
| Pode repetir o pedido | Repita o mesmo pedido no Location e use essa URL daqui em diante |
| Cabeçalhos relevantes |
|
O que significa o 308
O 308 foi criado pela RFC 7238 em 2014, virou Proposed Standard com a RFC 7538 em 2015 e hoje está na RFC 9110, seção 15.4.9. Ele tem o mesmo sentido do 301, uma nova URI permanente, mas proíbe a troca de POST por GET que os navegadores aplicam ao 301. Pode ir para o cache de forma heurística, então o navegador lembra dele como lembra de um 301.
O Google trata o 308 exatamente como o 301, um sinal forte de que o destino deve virar a URL canônica. O Next.js envia 308 por padrão nos redirects do next.config com permanent: true, no permanentRedirect() e na normalização de trailingSlash, então muitos sites emitem 308 sem nunca terem escolhido.
Todos os navegadores atuais e as bibliotecas HTTP mais usadas seguem o 308. A única lacuna antiga era o Internet Explorer 11 no Windows 7 e 8.1, que não entendia o código; se você ainda atende esses clientes, o 301 é a escolha conservadora para páginas acessadas com GET.
Quando usar
- Mudar de vez uma versão ou endpoint de API, como /api/v1/upload para /api/v2/upload, enquanto os clientes continuam mandando POST.
- Redirecionamentos de host canônico ou para HTTPS em sites que também recebem formulários ou webhooks.
- Qualquer lugar onde você usaria 301 mas precisa manter o método e o corpo.
Causas comuns
Se você está visitando o site
- ERR_TOO_MANY_REDIRECTS causado por uma regra 308 de barra ou de host brigando com outra regra; como o navegador guarda o 308, o loop pode continuar depois que o servidor foi corrigido.
Se você administra o servidor
- O trailingSlash do Next.js (ou um redirect com permanent: true) discordando de uma regra da CDN ou do proxy que coloca ou tira a barra no sentido contrário.
- Remetentes de webhook e clientes de API ainda chamando um endpoint antigo: o 308 mantém os clientes bem-comportados funcionando, mas alguns clientes HTTP não seguem redirecionamento em POST e registram o 308 como falha.
- Corpos enviados em streaming: o fetch() não consegue reenviar um corpo que era um ReadableStream, então um upload que encontra um 308 (ou um 307) falha em vez de ser redirecionado.
Como resolver
Se você está visitando o site
- Limpe os arquivos em cache do site para descartar um 308 antigo, ou teste a página numa janela anônima.
Se você administra o servidor
- Mapeie a cadeia com curl -sIL e faça as regras de barra e de host concordarem, aplicadas em uma única camada.
- Peça aos remetentes de webhook para atualizar a URL e mantenha o 308 até o tráfego para o caminho antigo acabar.
- Em uploads por streaming, chame a URL final diretamente em vez de depender do redirecionamento.
Como enviar um 308
// v1 is retired; clients keep POSTing, so the method must survive
app.use('/api/v1', (req, res) => {
// req.url is the path after the mount point, query string included
res.redirect(308, '/api/v2' + req.url);
});// next.config.js: permanent: true sends 308
module.exports = {
async redirects() {
return [
{ source: '/api/v1/:path*', destination: '/api/v2/:path*', permanent: true }
];
}
};
// In a route handler: Response.redirect(new URL('/api/v2/upload', request.url), 308)
// In pages and Server Components: permanentRedirect('/new') from next/navigationmux.HandleFunc("/api/v1/", func(w http.ResponseWriter, r *http.Request) {
target := "/api/v2/" + strings.TrimPrefix(r.URL.Path, "/api/v1/")
http.Redirect(w, r, target, http.StatusPermanentRedirect) // 308
})from fastapi import FastAPI
from fastapi.responses import RedirectResponse
app = FastAPI()
@app.api_route("/api/v1/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
def v1_moved(path: str):
return RedirectResponse(f"/api/v2/{path}", status_code=308)# rewrite ... permanent would send 301; return gives a 308
location ~ ^/api/v1/(.*)$ {
return 308 /api/v2/$1$is_args$args;
}Costuma ser confundido com
- 308 vs 301
- Mesma permanência e mesmo tratamento no SEO; o 301 deixa o cliente reenviar POST como GET, o 308 não.
- 308 vs 307
- O 307 também mantém o método, mas é temporário: não vai para o cache por padrão e não é sinal de URL canônica para buscadores.
Perguntas frequentes
- Qual a diferença entre 301 e 308?
- Os dois dizem que o recurso mudou de vez e os dois ficam no cache do navegador. O 301 deixa o cliente trocar POST por GET no pedido seguinte, e o navegador troca; o 308 exige o mesmo método e corpo.
- O redirecionamento 308 é bom para SEO?
- Sim. A documentação do Google coloca o 308 como equivalente ao 301: um sinal forte de que o destino do redirecionamento deve ser a URL canônica.
- Por que o Next.js responde 308 e não 301?
- O Next.js usa 308 nos redirects com permanent: true, no permanentRedirect() e no trailingSlash para que pedidos que não são GET mantenham o método. Se você precisa de um 301 literal, use statusCode: 301 no lugar de permanent no redirect do next.config.
- Todos os navegadores aceitam o status 308?
- Todos os navegadores atuais sim. O Internet Explorer 11 só seguia o 308 no Windows 10; no Windows 7 e 8.1 mostrava uma página de erro.
Revisado em por Arielton Oberek.