Por que razão uma empresa de proxy escreve sobre códigos de estado: somos a Geonode e as pessoas encaminham o tráfego da API através de nós, pelo que nos perguntam se um determinado erro se deve ao «proxy». No caso do 415, a resposta é, essencialmente, sempre «não». Um código 415 provém do servidor de origem e descreve algo sobre o pedido que criou. Um intermediário pode gerar um código 415 em circunstâncias muito específicas — um proxy de filtragem que inspeciona os corpos das mensagens, um gateway com as suas próprias regras de conteúdo — mas isso é pouco comum e é indicado nos cabeçalhos da resposta. Se estiver a receber um erro 415 através de um proxy, remova o proxy e, quase de certeza, receberá o mesmo erro 415 diretamente. Corrija a solicitação. O único código de estado que realmente implica um proxy é o 407, e isso está indicado no próprio nome.
Agora, o erro propriamente dito.
O que diz a especificação
A RFC 9110, na secção 15.5.16, define-o com precisão:
O código de estado 415 (Tipo de Mídia Não Suportado) indica que o servidor de origem se recusa a atender ao pedido porque o conteúdo está num formato não suportado por este método no recurso de destino.
Três partes dessa frase estão corretas.
«O conteúdo» — o corpo da solicitação, não o URL, nem a cadeia de consulta, nem a resposta. Se a sua solicitação não tiver corpo, um código 415 é invulgar e sugere que algo mais está a acontecer.
«Não suportado por este método» — o suporte é específico de cada método. Um recurso pode aceitar application/json num POST e rejeitá-lo num PATCH, o que é uma fonte de confusão verdadeiramente comum quando o mesmo ponto final se comporta de forma diferente consoante os verbos utilizados.
«No recurso de destino» — e por recurso. O facto de um ponto final de uma API aceitar um formato não diz nada sobre outro.
A especificação enumera então as causas:
O problema de formato pode dever-se ao Content-Type ou ao Content-Encoding indicado na solicitação, ou resultar da inspeção direta dos dados.
Essa última cláusula é importante e é frequentemente ignorada. Um servidor pode devolver um código de estado 415 após analisar os bytes, e não apenas após ler os cabeçalhos. Declarar «Content-Type: application/json» e enviar algo que não seja JSON pode, legitimamente, resultar num código de estado 415 em vez de um 400.
A RFC também especifica o que o servidor deve indicar. Se o problema fosse a codificação do conteúdo, diz que o cabeçalho de resposta «Accept-Encoding» «deve ser utilizado para indicar quais (se houver) as codificações de conteúdo que teriam sido aceites». Se fosse o tipo de mídia, «Accept» «pode ser utilizado para indicar quais os tipos de mídia que teriam sido aceites». Na prática, os documentos da MDN indicam que os servidores utilizam habitualmente Accept-Post e Accept-Patch para os casos específicos de métodos, o que é ainda mais útil.
Leia os cabeçalhos de resposta. Os servidores indicam frequentemente a resposta e os clientes ignoram-na frequentemente.
As seis causas
Por ordem aproximada da frequência com que as observamos.
1. Ausência total de Content-Type. Envia-se um corpo e nunca se declara o seu formato. Muitos frameworks não adivinham. O exemplo do MDN é exatamente este: um POST com um corpo JSON, um Content-Length e sem Content-Type, ao qual se responde com 415 e Accept-Post: application/json; charset=UTF-8.
2. O tipo de mídia (Content-Type) errado. O erro clássico é enviar JSON ao declarar application/x-www-form-urlencoded, normalmente porque um cliente HTTP utiliza por predefinição a codificação de formulário e você passou uma cadeia JSON sem a alterar. O corpo está correto; a etiqueta está errada.
3. Um tipo de mídia quase correto, mas errado. text/json em vez de application/json. application/xml quando o servidor espera text/xml. Tipos de fornecedor, como application/vnd.api+json, quando enviou application/json simples. Os servidores rigorosos fazem uma correspondência exata e não serão indulgentes.
4. Problemas com o conjunto de caracteres. O MDN dá o exemplo mais claro: enviar UTF8 quando o servidor exige UTF-8. O hífen não é opcional no nome registado, e um servidor que faça uma validação rigorosa dos parâmetros tem todo o direito de o rejeitar.
5. Content-Encoding que o servidor não suporta. Compacta-se o corpo da solicitação com gzip e define-se Content-Encoding: gzip num servidor que apenas suporta a codificação de identidade. A RFC prevê especificamente este caso, e um servidor que funcione corretamente deve devolver Accept-Encoding, indicando o que seria necessário.
6. O corpo não corresponde ao tipo declarado. Cabeçalho correto, bytes errados — frequentemente um erro de serialização, ou um modelo que emitiu uma cadeia de caracteres vazia, ou um corpo que foi codificado duas vezes algures na pilha. Esta é a cláusula «inspecionar os dados diretamente» em ação.
415 vs. 406 vs. 400 vs. 422
Este é o mapa de confusão, e a especificação distingue-os claramente.
| Código | O que significa | Direção | Corrigir alterando |
|---|
| 415 | O formato que enviou não é suportado | Corpo da solicitação | Content-Type ou Content-Encoding |
| 406 | Nenhuma representação que aceite está disponível | Resposta | Cabeçalho Accept |
| 400 | A solicitação está malformada | Solicitação completa | Sintaxe ou estrutura |
| 422 | Formato compreendido, conteúdo não processável | Corpo da solicitação | Os próprios dados |
| 413 | Corpo demasiado grande | Corpo da solicitação | Tamanho da carga útil |
415 versus 406 é uma questão de orientação e a mais fácil de compreender, uma vez explicada. O 415 diz respeito ao que enviou. O 406 diz respeito ao que pediu para receber — a RFC 9110 define-o como o recurso não ter «uma representação atual que seja aceitável para o agente do utilizador, de acordo com os campos de cabeçalho de negociação proativa recebidos». Se estiver a receber um 406, verifique o seu cabeçalho «Accept», e não o corpo da mensagem.
415 versus 400. A RFC 9110 descreve o código 400 como o servidor não processar a solicitação «devido a algo que é percebido como um erro do cliente (por exemplo, sintaxe da solicitação malformada, estrutura inválida da mensagem de solicitação ou encaminhamento enganoso da solicitação)». O código 400 é estrutural — a própria solicitação está incorreta. O código 415 refere-se a uma solicitação bem formada cujo corpo está num formato que o servidor não aceita. Na prática, muitos servidores devolvem um 400 quando um 415 seria mais preciso; não é possível controlar isto, por isso trate um 400 numa solicitação com corpo como possivelmente um 415 disfarçado.
415 versus 422 é a distinção que a RFC estabelece de forma mais explícita. A secção 15.5.21 afirma que o 422 indica que «o servidor compreende o tipo de conteúdo da solicitação (pelo que um código de estado 415 (Tipo de Mídia Não Suportado) é inadequado) e que a sintaxe do conteúdo da solicitação está correta, mas não conseguiu processar as instruções nela contidas».
Portanto, a hierarquia é a seguinte: 415 significa que o invólucro está errado; 422 significa que o invólucro está correto e o conteúdo está errado. Um JSON bem formado em que falte um campo obrigatório resulta num 422. O mesmo JSON rotulado como dados de formulário resulta num 415.
Diagnosticar o problema em menos de dois minutos
Uma sequência fixa que resolve quase todos os casos.
Primeiro passo: ler os cabeçalhos da resposta. Não a linha de estado, mas sim os cabeçalhos.
curl -i -X POST https://api.example.com/items \
-H "Content-Type: application/json" \
-d '{"name":"test"}'
Procure por Accept, Accept-Post, Accept-Patch ou Accept-Encoding na resposta. Se algum destes estiver presente, é uma indicação direta do que o servidor pretende e o processo está concluído.
Passo dois: confirme o que realmente enviou. Não o que pretendia enviar — mas sim o que foi efetivamente transmitido. As bibliotecas de cliente adicionam, substituem e reformatam cabeçalhos, e o cabeçalho que definiu no código nem sempre é o que foi transmitido.
curl -v -X POST https://api.example.com/items \
-H "Content-Type: application/json" \
-d '{"name":"test"}' 2>&1 | grep '^>'
As linhas «>» constituem o seu pedido efetivo. Uma percentagem surpreendente de erros 415 é resolvida precisamente aqui, quando o «Content-Type» que definiu cuidadosamente acaba por ter sido substituído por um valor predefinido.
Passo três: verifique o método. O mesmo endpoint pode aceitar um tipo num POST e rejeitá-lo num PATCH. Experimente o mesmo corpo com um verbo diferente e veja se o comportamento muda.
Passo quatro: verifique a string exata do tipo. Compare caractere a caractere com a documentação. application/json versus text/json. UTF-8 versus UTF8. Sufixos do fornecedor. Isto é tedioso, mas é aqui que muitas vezes se encontra a resposta.
Passo cinco: ler a documentação relativa a esse ponto de extremidade específico. As APIs não são uniformes internamente. Um ponto de extremidade de carregamento de ficheiros que exija multipart/form-data numa API que, de resto, é JSON, é perfeitamente normal.
Resolver o problema no lado do cliente
Os casos mais comuns nos clientes mais comuns.
curl. -d implica application/x-www-form-urlencoded, a menos que se indique o contrário. Esta é a causa mais comum de um erro 415 na linha de comandos:
curl -X POST https://api.example.com/items \
-H "Content-Type: application/json" \
-d '{"name":"test"}'
JavaScript fetch. Ao passar um corpo de string, não se define Content-Type de todo:
await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "test" }),
});
A exceção que vale a pena conhecer: com FormData, não defina Content-Type manualmente. O navegador deve gerá-lo porque inclui o limite multipart, e substituí-lo produz uma solicitação incorreta que frequentemente se manifesta como um erro 415.
Solicitações em Python. Utilize json= em vez de data= e o cabeçalho é definido automaticamente:
requests.post(url, json={"name": "test"}) # application/json
requests.post(url, data={"name": "test"}) # form-encoded
Axios. Define application/json para objetos simples e algo diferente para cadeias de caracteres, o que é uma fonte frequente de surpresas. Se já tiver serializado a sua carga útil, defina o cabeçalho explicitamente. As diferenças de comportamento entre os clientes neste contexto são exatamente o tipo de assunto que abordámos em axios vs fetch.
Regra geral: quando um cliente disponibilizar um parâmetro específico para JSON, utilize-o em vez de serializar manualmente e esperar que o cabeçalho predefinido esteja correto.
Responder corretamente do lado do servidor
Se estiveres do outro lado, há alguns aspetos que tornam a tua API consideravelmente mais fácil de utilizar.
Envia um cabeçalho «Accept-Post» ou «Accept-Patch» juntamente com o código 415. A RFC pede «Accept» ou «Accept-Encoding»; as variantes específicas do método são mais precisas e a MDN documenta-as exatamente para esta finalidade. Este único cabeçalho transforma uma sessão de depuração numa análise rápida.
Inclua um corpo legível. Um código de estado com um corpo vazio obriga o cliente a adivinhar. Indique o que recebeu e o que esperava.
Distinga corretamente o 415 do 422. Se compreendeu o tipo de conteúdo e o corpo foi analisado, mas falhou na validação, isso é um 422. Devolver um 415 por falhas de validação leva as pessoas a verificarem os seus cabeçalhos quando estes estavam corretos, e é um erro comum e dispendioso na conceção de APIs.
Seja tolerante em relação aos parâmetros sempre que for seguro fazê-lo. Rejeitar application/json; charset=utf-8 quando aceita application/json é tecnicamente defensável, mas, na prática, inútil. Analise o tipo de mídia corretamente e ignore os parâmetros que não lhe interessam.
Não utilize o código 415 como uma rejeição genérica. Ele tem um significado específico. Sobrecarregá-lo torna a sua API mais difícil de utilizar e faz com que a lógica de repetição do cliente fique incorreta.
Quando um 415 não é realmente um 415
Casos em que o código de estado induz em erro.
Um gateway ou WAF rejeitou o pedido. Algumas camadas de segurança devolvem o código 415 para corpos de pedido que consideram suspeitos, independentemente do tipo de conteúdo real. A pista é, normalmente, um corpo de resposta que não parece ter vindo da aplicação, ou cabeçalhos que identificam um intermediário.
Uma configuração predefinida do framework foi acionada antes do seu código ser executado. Muitos frameworks web rejeitam tipos de conteúdo desconhecidos no middleware. O seu handler nunca foi executado, pelo que nada na lógica da sua aplicação é relevante para a correção.
Um balanceador de carga ou uma CDN removeu um cabeçalho. Raro, mas real. Se a solicitação funcionar quando enviada diretamente e falhar ao passar pela infraestrutura, compare os cabeçalhos em ambas as extremidades antes de assumir que a aplicação sofreu alterações.
O endpoint não existe. Alguns servidores respondem a uma rota não correspondente num POST com o código de estado 415 em vez de 404, porque a negociação do tipo de conteúdo ocorre antes da resolução do encaminhamento. Verifique o URL.
A substituição do método HTTP correu mal. Se a sua estrutura suportar a substituição do método através de um cabeçalho ou parâmetro de consulta, o método efetivo pode não ser aquele que enviou, e o suporte ao tipo de conteúdo é específico para cada método.
Em cada um destes casos, a correção situa-se a montante da sua carga útil. O princípio geral: se o pedido estiver obviamente correto e o erro 415 persistir, pare de editar o corpo da solicitação e comece a descobrir qual o componente no caminho que está a gerar a resposta.
Perguntas frequentes
O que significa o erro 415 «Unsupported Media Type»?
O servidor recusou o pedido porque o formato do corpo do pedido não é suportado para esse método nesse recurso. A norma RFC 9110 atribui esta situação ao cabeçalho «Content-Type», ao cabeçalho «Content-Encoding» ou à inspeção direta do corpo do pedido pelo servidor. Trata-se do formato do que enviou, não da correção dos dados.
Como corrijo um erro 415?
Verifique primeiro os cabeçalhos da resposta — os servidores devolvem frequentemente Accept, Accept-Post ou Accept-Encoding, indicando exatamente o que pretendem. Em seguida, verifique o que o seu cliente transmitiu efetivamente, uma vez que as bibliotecas substituem os cabeçalhos. A correção mais comum consiste em adicionar Content-Type: application/json a uma solicitação que não o tivesse.
Qual é a diferença entre 415 e 400?
400 significa que a solicitação está malformada — sintaxe ou estrutura incorretas. 415 significa que a solicitação está bem formada, mas o corpo está num formato não suportado. Na prática, os servidores costumam devolver um código 400 quando um 415 seria mais preciso; por isso, um código 400 numa solicitação com corpo merece ser investigado como um possível problema de tipo de conteúdo.
Qual é a diferença entre 415 e 422?
A RFC 9110 estabelece esta distinção explicitamente: 422 significa que o servidor compreendeu o tipo de conteúdo e que a sintaxe estava correta, mas não conseguiu processar as instruções. Assim, 415 indica que o «wrapper» está errado; 422 indica que o conteúdo está errado. Um JSON válido em que falte um campo obrigatório resulta num 422.
Por que recebo um erro 415 ao carregar ficheiros?
Normalmente, porque o cabeçalho «Content-Type» foi definido manualmente numa solicitação multipart. O navegador ou cliente deve gerar esse cabeçalho por si próprio, pois contém o delimitador multipart. Definir esse cabeçalho manualmente remove o delimitador e produz uma solicitação que o servidor não consegue analisar.
Um proxy pode causar um erro 415?
Raramente. O erro 415 provém do servidor de origem e refere-se ao corpo da sua solicitação. Um proxy de filtragem ou um gateway que inspecione o conteúdo pode gerar esse erro, mas o código de estado específico de proxy habitual é o 407, o que já está indicado no próprio nome. Teste sem o proxy — se o erro 415 persistir, o proxy não esteve envolvido.
O erro 415 significa que o meu JSON é inválido?
Não necessariamente. Se o servidor rejeitou o tipo de conteúdo, o seu JSON nunca foi analisado. Se o servidor declarou o tipo correto e, em seguida, verificou que o corpo não estava, de facto, nesse formato, então sim — a RFC permite a rejeição após «inspecionar os dados diretamente». Verifique primeiro a questão do cabeçalho; é muito mais comum.
Devo tentar novamente após um erro 415?
Não. Trata-se de um erro do cliente e a mesma solicitação produzirá o mesmo resultado. Tentar novamente desperdiça solicitações e, se estiver sujeito a limites de taxa, pode piorar a situação. Corrija o tipo de conteúdo e envie uma única vez.
Conclusão
O código de erro 415 tem um significado restrito e preciso: o «wrapper» em torno dos seus dados não é um dos que este endpoint aceita para este método. Não se trata de os seus dados serem inválidos — para isso existe o código 422 —, nem do que solicitou receber — para isso existe o código 406.
Como o significado é restrito, o diagnóstico é breve. Leia os cabeçalhos da resposta, pois um servidor que funcione corretamente indica os tipos aceitáveis em Accept, Accept-Post ou Accept-Encoding. Em seguida, verifique o que o seu cliente realmente enviou, em vez do que lhe pediu para enviar, uma vez que as predefinições e o middleware substituem frequentemente o cabeçalho que definiu. Entre estes dois passos, resolverá a maioria dos casos sem ter de mexer no corpo da mensagem.
E se o pedido parecer irrepreensível e o erro 415 persistir, a resposta provavelmente não está a vir da aplicação que pensa que é. Gateways, middleware de frameworks e rotas não correspondentes produzem todos erros 415 que nada têm a ver com a sua carga útil — e, nessa altura, a questão relevante não é o que alterar, mas sim qual o componente no caminho que está a responder.