Código de status HTTP · Redirecionamento (3xx)
300 Multiple Choices
O status 300 Multiple Choices indica que o recurso tem mais de uma representação, como o mesmo documento em formatos ou idiomas diferentes, e o servidor quer que o cliente escolha. Na prática ele quase só aparece em configurações de negociação de conteúdo, como o MultiViews do Apache, quando nenhuma variante ganha das outras.
| Classe | 3xx, Redirecionamento |
|---|---|
| Definido em | RFC 9110 §15.4.1 |
| Pode ir para o cache por padrão | Sim, de forma heurística |
| Pode repetir o pedido | Escolha uma das alternativas listadas, ou siga o Location se o servidor enviou um |
| Cabeçalhos relevantes |
|
O que significa o 300
A RFC 9110, seção 15.4.1, descreve o 300 como negociação reativa: em vez de escolher uma representação, o servidor lista as alternativas e deixa o usuário ou o cliente seguir a que preferir. Se o servidor tiver uma favorita, deve indicá-la no cabeçalho Location, e o cliente pode segui-la automaticamente.
A especificação nunca definiu um formato para essa lista, então o navegador só mostra o corpo da resposta e deixa a escolha para quem está lendo. Por isso o código é raro: a negociação proativa, em que o servidor lê Accept e Accept-Language e decide sozinho, venceu em quase todo lugar. Ao contrário da maioria dos 3xx, o 300 pode ser guardado em cache de forma heurística.
Quando usar
- Só quando o servidor realmente não consegue decidir e a escolha humana é aceitável, por exemplo um conjunto de dados oferecido em CSV, JSON e Parquet para um cliente que não mandou um Accept útil.
- Envie um Location com a variante preferida, para que clientes que seguem sozinhos caiam em algo razoável, e uma lista curta em HTML ou JSON com as alternativas no corpo.
Causas comuns
Se você administra o servidor
- O mod_negotiation do Apache com Options +MultiViews encontra vários arquivos que servem igualmente bem, como relatorio.en.html e relatorio.pt.html, e responde 300 com uma lista em vez de escolher.
Como resolver
Se você está visitando o site
- Clique na versão que você quer na lista mostrada pela página; o servidor está esperando essa escolha.
Se você administra o servidor
- Adicione ForceLanguagePriority Prefer Fallback com uma lista em LanguagePriority para o Apache servir uma variante, ou desligue o MultiViews e use URLs explícitas.
- Em APIs, negocie pelo Accept e responda 200 com o formato escolhido, ou 406 quando nenhum servir.
Como enviar um 300
app.get('/datasets/:name', (req, res) => {
res.set('Location', '/datasets/sales.csv');
res.status(300).json({ choices: ['/datasets/sales.csv', '/datasets/sales.json', '/datasets/sales.parquet'] });
});// app/datasets/[name]/route.ts
export async function GET() {
return Response.json(
{ choices: ['/datasets/sales.csv', '/datasets/sales.json', '/datasets/sales.parquet'] },
{ status: 300, headers: { 'Location': '/datasets/sales.csv' } }
);
}mux.HandleFunc("GET /datasets/{name}", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", "/datasets/sales.csv")
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusMultipleChoices) // 300
w.Write([]byte(`{"choices":["/datasets/sales.csv","/datasets/sales.json","/datasets/sales.parquet"]}`))
})from fastapi import FastAPI
from fastapi.responses import JSONResponse
app = FastAPI()
@app.get("/datasets/{name}")
def get_dataset(name: str):
return JSONResponse(status_code=300, content={"choices": ["/datasets/sales.csv", "/datasets/sales.json", "/datasets/sales.parquet"]}, headers={"Location": "/datasets/sales.csv"})Costuma ser confundido com
- 300 vs 406
- O 406 Not Acceptable diz que nenhuma representação atende ao que o cliente pediu; o 300 diz que várias servem e o cliente deve escolher.
- 300 vs 302
- O 302 aponta para uma única outra URL; o 300 oferece um cardápio delas.
Perguntas frequentes
- O navegador segue um 300 Multiple Choices sozinho?
- Só quando a resposta traz um cabeçalho Location, e mesmo assim depende do cliente. Sem Location, o navegador mostra o corpo como uma página comum, então ele precisa ter links clicáveis para cada alternativa.
- Por que o Apache responde 300 Multiple Choices?
- A negociação de conteúdo do MultiViews achou vários arquivos para o nome pedido com a mesma pontuação frente aos cabeçalhos da requisição. O ForceLanguagePriority Prefer faz o Apache escolher um pela LanguagePriority em vez de perguntar.
- Uma API REST deve usar 300 Multiple Choices?
- Quase nunca. APIs costumam negociar pelo cabeçalho Accept e responder 200 no formato escolhido, ou 406 quando nada serve. Um 300 obriga cada cliente a implementar uma etapa de escolha que nenhum padrão descreve.
Revisado em por Arielton Oberek.