Skip to content

Código de status HTTP · Redirecionamento (3xx)

303 See Other

O status 303 See Other manda o cliente buscar outra URL, indicada no Location, com um GET, como resposta ao que ele acabou de fazer. O uso clássico é o padrão Post/Redirect/Get: depois do POST de um formulário, o servidor redireciona para uma página de resultado, e atualizar a página não envia o formulário de novo.

Dados sobre este código de status
Classe3xx, Redirecionamento
Definido emRFC 9110 §15.4.4
Pode ir para o cache por padrãoSó com Cache-Control ou Expires explícitos
Pode repetir o pedidoNão repita o pedido original; faça um GET na URL do Location
Cabeçalhos relevantes
  • Location: outro recurso que descreve o resultado, buscado com GET

O que significa o 303

A RFC 9110, seção 15.4.4, faz do 303 o único redirecionamento que sempre significa GET (ou HEAD) em seguida, seja qual for o método original, e diz que ele vale para qualquer método. Ele surgiu porque o 302 era ambíguo nos anos 1990: alguns navegadores reenviavam o POST, outros trocavam para GET. Com o 303 não há o que adivinhar.

A URL do Location não é um novo endereço do recurso original; é outro recurso que descreve o resultado, como /pedidos/1042 depois de POST /pedidos. Essa página de resultado pode ser salva nos favoritos, compartilhada e guardada em cache por conta própria, coisa que uma resposta a POST não permite. O 303 em si só vai para o cache se tiver cabeçalhos de validade explícitos.

Quando usar

  • Depois de um POST de formulário bem-sucedido (cadastro, checkout, comentário), para mostrar a página de resultado com GET.
  • Depois de aceitar uma tarefa demorada, apontando o cliente para o recurso de status ou de resultado.
  • No Next.js, redirect() dentro de uma Server Action já responde 303, então você ganha o Post/Redirect/Get sem escolher código.

Causas comuns

Se você administra o servidor

  • No FastAPI ou Starlette, devolver RedirectResponse depois de um POST de formulário sem status_code: o padrão é 307, então o navegador envia o formulário de novo por POST para a URL de resultado, que responde 405 Method Not Allowed.
  • Usar 302 depois de um POST funciona nos navegadores, mas deixa outros clientes HTTP livres para repetir o POST na nova URL.

Como resolver

Se você administra o servidor

  • Responda 303 explicitamente depois de qualquer POST que altera dados e deve terminar numa página, e faça do destino uma rota GET comum.
  • Faça o trabalho antes de redirecionar: se o POST falhar, responda 4xx com o formulário e os erros, não um 303.

Como enviar um 303

Express (Node.js)
app.post('/orders', async (req, res) => {
  const order = await createOrder(req.body);
  // The browser loads the receipt with GET; refresh will not re-submit
  res.redirect(303, `/orders/${order.id}`);
});
Next.js App Router (route handler)
// app/orders/route.ts
export async function POST(request: Request) {
  const order = await createOrder(await request.formData());
  return Response.redirect(new URL(`/orders/${order.id}`, request.url), 303);
}

// In a Server Action, redirect() from next/navigation already sends 303.
Go net/http
mux.HandleFunc("POST /orders", func(w http.ResponseWriter, r *http.Request) {
	id, err := createOrder(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	http.Redirect(w, r, "/orders/"+id, http.StatusSeeOther) // 303
})
Python FastAPI
from fastapi import FastAPI, Form
from fastapi.responses import RedirectResponse

app = FastAPI()

@app.post("/orders")
def create_order(product_id: int = Form(...)):
    order = save_order(product_id)
    # Without status_code=303 the default 307 would re-POST the form
    return RedirectResponse(f"/orders/{order.id}", status_code=303)

Costuma ser confundido com

303 vs 302
O 302 só tolera a troca para GET por motivos históricos; o 303 exige a troca, deixando a intenção clara para qualquer cliente.
303 vs 307
O 307 tem a regra oposta: repetir o mesmo método e corpo. Depois do POST de um formulário, isso significa enviá-lo de novo.
303 vs 201
O 201 Created responde o POST diretamente e aponta o novo recurso no Location; o 303 manda o cliente fazer GET numa página sobre o resultado.

Perguntas frequentes

Quando usar 303 em vez de 302?
Sempre que o redirecionamento vier depois de um POST, PUT ou DELETE e o cliente deva carregar uma página de resultado com GET. Nesse caso o navegador trata os dois igual, mas o 303 declara a intenção no protocolo, e clientes de API e bibliotecas não precisam adivinhar.
Uma API REST deve responder 201 ou 303 depois de um POST?
Responda 201 Created com o cabeçalho Location e, normalmente, o novo recurso no corpo. O 303 se encaixa melhor quando o resultado já existe, como um envio duplicado apontando para o registro que já estava lá.
O 303 também transforma PUT e DELETE em GET?
Sim. A RFC 9110 diz que o 303 vale para qualquer método, e o padrão Fetch que os navegadores seguem troca o método para GET e descarta o corpo em todos os casos, exceto HEAD.

Revisado em por Arielton Oberek.