O que significa “Tipo de conteúdo: application / json; charset = utf-8 ”realmente significa?

284

Quando faço uma solicitação POST com um corpo JSON para o meu serviço REST, incluo Content-type: application/json; charset=utf-8no cabeçalho da mensagem. Sem esse cabeçalho, recebo um erro do serviço. Eu também posso usar com sucesso Content-type: application/jsonsem a ;charset=utf-8parte.

O que exatamente faz charset=utf-8? Eu sei que especifica a codificação de caracteres, mas o serviço funciona bem sem ele. Essa codificação limita os caracteres que podem estar no corpo da mensagem?

DenaliHardtail
fonte
4
dê uma olhada em hanselman.com/blog/…
Daniel Powell
8
Curiosamente, de acordo com o application/jsonRegistro de tipo de mídia da IANA , não parece haver nenhum charsetparâmetro suportado , embora seja frequentemente fornecido na prática.
uux
1
I know it specifies the character encoding but the service works fine without it."trabalhar" nem sempre significa "o código / configuração existente é a maneira mais correta de cobrir todos os casos de canto para fazer uma coisa". Depende de todas as convenções e premissas que podem não funcionar em outras circunstâncias. Para mim, pessoalmente, sempre tento ser o mais explícito possível.
WesternGun 15/04/19
3
O envio de um parâmetro "charset" está incorreto e sem sentido. Veja RFC 8259, Seção 11, última frase.
Julian Reschke

Respostas:

283

O cabeçalho apenas indica em que o conteúdo está codificado. Não é necessariamente possível deduzir o tipo de conteúdo do próprio conteúdo, ou seja, você não pode necessariamente olhar apenas para o conteúdo e saber o que fazer com ele. É para isso que servem os cabeçalhos HTTP, eles dizem ao destinatário que tipo de conteúdo eles estão (supostamente) lidando.

Content-type: application/json; charset=utf-8designa o conteúdo para estar no formato JSON, codificado na codificação de caracteres UTF-8. A designação da codificação é um pouco redundante para JSON, pois a codificação padrão (apenas?) Para JSON é UTF-8. Portanto, nesse caso, o servidor de recebimento aparentemente fica feliz sabendo que está lidando com JSON e assume que a codificação é UTF-8 por padrão, é por isso que funciona com ou sem o cabeçalho.

Essa codificação limita os caracteres que podem estar no corpo da mensagem?

Não. Você pode enviar o que quiser no cabeçalho e no corpo. Mas, se os dois não corresponderem, você poderá obter resultados errados. Se você especificar no cabeçalho que o conteúdo é codificado em UTF-8, mas na verdade você está enviando conteúdo codificado em Latin1, o destinatário poderá produzir dados de lixo, tentando interpretar os dados codificados em Latin1 como UTF-8. Se, é claro, você especificar que está enviando dados codificados em Latin1 e realmente o está fazendo, então sim, você está limitado aos 256 caracteres que pode codificar em Latin1.

deceze
fonte
4
Obviamente, no JSON você ainda pode representar caracteres não-Latin1 usando sequências de escape como \u20AC.
22412 dan04
31
De acordo com o padrão para json, você não tem permissão para usar latin1 na codificação do conteúdo. O conteúdo JSON deve ser codificado como unicode, seja UTF-8, UTF-16 ou UTF-32 (big ou little endian).
Daniel Luna
20
Não há parâmetro charset no aplicativo / json.
Julian Reschke
7
@DanielLuna está certo, application/json precisa estar em um dos formatos de transformação do ucs. Além disso, como os quatro primeiros bytes do JSON são limitados, você sempre pode saber se são 8, 16 ou 32 e se há endianidade.
Jason Coco
4
Evento, se for redundante, você pode querer incluir charset=utf-8por motivos de segurança: github.com/shieldfy/API-Security-Checklist/issues/25
manuc66
143

Para comprovar a afirmação de @ deceze de que a codificação JSON padrão é UTF-8 ...

De IETF RFC4627 :

O texto JSON DEVE ser codificado em Unicode. A codificação padrão é UTF-8.

Como os dois primeiros caracteres de um texto JSON sempre serão caracteres ASCII [RFC0020], é possível determinar se um fluxo de octetos é UTF-8, UTF-16 (BE ou LE) ou UTF-32 (BE ou LE) observando o padrão de nulos nos quatro primeiros octetos.

      00 00 00 xx  UTF-32BE
      00 xx 00 xx  UTF-16BE
      xx 00 00 00  UTF-32LE
      xx 00 xx 00  UTF-16LE
      xx xx xx xx  UTF-8
Drew Noakes
fonte
12
Sempre ajuda pensar no JSON como formato binário, não como formato de texto.
Sulthan
2
Agora que o RFC4627 foi obsoleto pelo RFC7159, que afirma que o valor raiz pode ser uma string (em contraste explícito com a especificação anterior), como isso agora é implementado? A especificação é vaga a esse respeito, e apenas diz que três codificações são permitidas, mas não como se deve diferenciá-las.
Fabio Beltramini
4
@FabioBeltramini O exemplo acima ainda deve ser mantido, porque uma string no JSON não conterá caracteres nulos literais (os nulos no JSON precisariam ser codificados com uma sequência de escape numérica, por exemplo "\u0000").
thomasrutter
3
Na verdade, o segundo caractere em UTF-16xx pode não ter um NULL nesse caso, mas ainda será possível determinar a codificação dos outros bytes: xx 00 00 00ainda é UTF-32LE e xx 00 xx xxainda é UTF-16LE, 00 xx xx xxainda é UTF-16BE.
thomasrutter
20

Observe que o IETF RFC4627 foi substituído pelo IETF RFC7158 . Na seção [8.1], ele retrai o texto citado por @Drew anteriormente, dizendo:

Implementations MUST NOT add a byte order mark to the beginning of a JSON text.
Alex
fonte
A suposição ainda é válida, pois qualquer json válido ainda começará com dois caracteres ascii.
Larsing
Um caractere, porque um único numeral é um arquivo JSON válido
Nayuki 28/10/19
0

Concordo exatamente com o @deceze, mas quero desenvolver essa parte da pergunta "Recebo um erro do serviço" ,

Estamos recebendo esse tipo de erro como http 415

Http 415 Erro de tipo de mídia não suportado

O código de resposta de erro do cliente Tipo de mídia não suportado HTTP 415 indica que o servidor se recusa a aceitar a solicitação porque o formato da carga útil está em um formato não suportado.

O problema de formato pode ser devido ao Tipo de Conteúdo ou Codificação de Conteúdo indicado pela solicitação ou como resultado da inspeção direta dos dados.

Em outras palavras, como visto em https://stackoverflow.com/a/22643964/914284 neste exemplo.

  • Temos que definir o tipo de conteúdo correto e aceitar o tipo de conteúdo correto, como visto Adicionar tipo de conteúdo: application / json e Accept: application / json. Caso contrário, ele assumirá o padrão
Hamit YILDIRIM
fonte
0

A implementação do http dardo processa os bytes graças a esse "charset = utf-8", por isso tenho certeza de que várias implementações suportam isso, para evitar o charset de retorno "latin-1" ao ler os bytes da resposta. No meu caso, perco totalmente o formato na string do corpo da resposta, portanto, tenho que fazer a codificação de bytes manualmente para utf8 ou adicionar esse parâmetro "interno" do cabeçalho na resposta da API do meu servidor.

roipeker
fonte
0

Eu estava usando HttpClient e voltando ao cabeçalho de resposta com o tipo de conteúdo application/json, perdi caracteres como idiomas estrangeiros ou símbolo que usava unicode, pois o HttpClient é o padrão ISO-8859-1 . Portanto, seja explícito quanto possível, conforme mencionado por @WesternGun para evitar qualquer possível problema.

Não há como lidar com isso devido ao servidor não manipular o cabeçalho solicitado charset ( method.setRequestHeader("accept-charset", "UTF-8");) para mim e eu tive que recuperar dados de resposta como bytes de desenho e convertê-los em String usando UTF-8. Portanto, é recomendável ser explícito e evitar a suposição do valor padrão.

Tri Nguyen
fonte