Codificação de caracteres JSON - UTF-8 é bem suportado por navegadores ou devo usar sequências de escape numéricas?

91

Estou escrevendo um serviço da web que usa json para representar seus recursos e estou um pouco preso a pensar sobre a melhor maneira de codificar o json. Lendo o json rfc ( http://www.ietf.org/rfc/rfc4627.txt ), fica claro que a codificação preferida é utf-8. Mas o rfc também descreve um mecanismo de escape de string para especificar caracteres. Suponho que isso geralmente seria usado para escapar caracteres não-ascii, tornando o utf-8 ascii válido.

Então, digamos que eu tenha uma string json que contém caracteres Unicode (pontos de código) que não são ASCII. O meu serviço da web deve apenas codificar em utf-8 e retorná-lo ou deve escapar de todos os caracteres não ASCII e retornar ASCII puro?

Eu gostaria que os navegadores pudessem executar os resultados usando jsonp ou eval. Isso afeta a decisão? Meu conhecimento de suporte a javascript de vários navegadores para utf-8 é insuficiente.

EDIT: Eu queria esclarecer que minha principal preocupação sobre como codificar os resultados é realmente sobre como o navegador manipula os resultados. O que li indica que os navegadores podem ser sensíveis à codificação ao usar JSONP em particular. Não encontrei nenhuma informação realmente boa sobre o assunto, então terei que começar a fazer alguns testes para ver o que acontece. Idealmente, gostaria de apenas escapar aqueles poucos caracteres que são necessários e apenas utf-8 codificar os resultados.

schickb
fonte

Respostas:

89

A especificação JSON requer suporte UTF-8 por decodificadores. Como resultado, todos os decodificadores JSON podem lidar com UTF-8 tão bem quanto podem lidar com as sequências de escape numéricas. Este também é o caso para intérpretes Javascript, o que significa que JSONP lidará com o JSON codificado em UTF-8 também.

A capacidade dos codificadores JSON de usar as sequências de escape numéricas apenas oferece mais opções. Uma razão pela qual você pode escolher as sequências de escape numéricas seria se um mecanismo de transporte entre o seu codificador e o decodificador pretendido não é seguro para binários.

Outro motivo pelo qual você pode querer usar sequências de escape numéricas é evitar que certos caracteres apareçam no fluxo, como <, &e ", que podem ser interpretados como sequências HTML se o código JSON for colocado sem escapar em HTML ou um navegador interpretá-lo incorretamente como HTML . Isso pode ser uma defesa contra injeção de HTML ou script entre sites (observação: alguns caracteres DEVEM ter escape em JSON, incluindo "e \).

Alguns frameworks, incluindo a implementação de JSON em PHP, sempre fazem as sequências de escape numéricas no lado do codificador para qualquer caractere fora de ASCII. Isso se destina a compatibilidade máxima com mecanismos de transporte limitados e semelhantes. No entanto, isso não deve ser interpretado como uma indicação de que os decodificadores JSON têm problemas com UTF-8.

Então, acho que você pode decidir qual usar assim:

  • Basta usar UTF-8, a menos que seu método de armazenamento ou transporte entre o codificador e o decodificador não seja seguro para binários.

  • Caso contrário, use as sequências de escape numéricas.

Thomasrutter
fonte
1
"todos os decodificadores JSON podem lidar com UTF-8" Embora isso seja verdade para os navegadores, só porque o padrão exige isso não significa que todos os softwares de decodificação JSON suportam UTF-8.
Michael Mior
7
"Todos os decodificadores JSON podem lidar com UTF-8" é literalmente verdade. Se algo não aceita UTF-8, não é um decodificador JSON. Pode ser semelhante a um decodificador JSON, mas definitivamente não é.
thomasrutter
Acho que depende da definição de decodificador JSON que você está usando, mas ponto justo :)
Michael Mior
A razão pela qual a RFC 8259 especifica o suporte UTF-8 como obrigatório é que é o que o mundo padronizou. As especificações obsoletas anteriores definiam as strings como Unicode, mas não especificavam qual codificação; implementações padronizadas em UTF-8 de qualquer maneira e as especificações atualizadas refletem isso.
thomasrutter
O suporte a UTF-8 não é especificado como obrigatório naquela RFC para nenhum software específico, pelo que eu sei. A única menção ao UTF-8 é que ele deve ser usado como codificação para JSON trocado fora de um sistema fechado. Isso não significa que todos os decodificadores JSON (uma linguagem não usada no RFC) devem oferecer suporte a UTF-8.
Michael Mior
17

Tive um problema aí. Quando eu codifico JSON uma string com um caractere como "é", todos os navegadores retornarão o mesmo "é", exceto o IE que retornará "\ u00e9".

Então, com PHP json_decode (), ele falhará se encontrar "é", então para Firefox, Opera, Safari e Chrome, tenho que chamar utf8_encode () antes de json_decode ().

Nota: com meus testes, o IE e o Firefox estão usando seu objeto JSON nativo, outros navegadores estão usando json2.js.

Tim Tisdall
fonte
10
Provavelmente você quis dizer utf8_encode(), php.net/manual/en/function.utf8-encode.php
Binyamin
4
Se o IE não consegue decodificar isso, é um bug em qualquer decodificador JSON que você está usando. Todos os decodificadores JSON devem decodificar com sucesso a forma codificada, ou eles não são um decodificador JSON. Quanto ao seu problema com json_decode () com o é unescaped, é possível que o texto que você está alimentando não seja UTF-8. Os decodificadores JSON sempre assumem UTF-8, mesmo a implementação do PHP, embora o PHP normalmente não assuma UTF-8 em muitas outras funções. Existem outras codificações de caracteres que podem incluir um é sem escape e parecer idênticas na tela, mas que não são UTF-8. Codificar no formato \ uXXXX é uma solução alternativa para isso.
thomasrutter
Apenas dizendo: JSON pode vir legalmente em qualquer codificação Unicode (UTF-8, UTF-16 BE / LE, UTF32 BE / LE, com ou sem marcador de ordem de byte). E como o ASCII é um subconjunto do UTF-8, também pode vir em ASCII. Se os analisadores aceitam UTF-32, por exemplo, não sei.
gnasher729 01 de
1
Isso está correto, e os analisadores não precisam oferecer suporte a nada além de UTF-8. Da especificação: "O texto JSON DEVERÁ ser codificado em UTF-8, UTF-16 ou UTF-32. A codificação padrão é UTF-8 e os textos JSON codificados em UTF-8 são interoperáveis ​​no sentido de que irão ser lido com sucesso pelo número máximo de implementações; há muitas implementações que não conseguem ler textos em outras codificações (como UTF-16 e UTF-32). As implementações NÃO DEVEM adicionar uma marca de ordem de bytes no início de um texto JSON. "
thomasrutter
@thomasrutter A especificação que você citou é antiga. A especificação atual diz: " Texto JSON trocado entre sistemas que não fazem parte de um ecossistema fechado DEVE ser codificado usando UTF-8. Especificações anteriores de JSON não exigiam o uso de UTF-8 ao transmitir texto JSON. No entanto, a grande maioria de implementações de software baseado em JSON optaram por usar a codificação UTF-8, na medida em que é a única codificação que atinge a interoperabilidade. As implementações NÃO DEVEM adicionar uma marca de ordem de byte (U + FEFF) ao início de uma transmissão em rede JSON text. "
Remy Lebeau,
12

ASCII não está mais nele. Usar a codificação UTF-8 significa que você não está usando a codificação ASCII. Você deve usar o mecanismo de escape para o que diz o RFC:

Todos os caracteres Unicode podem ser colocados entre aspas, exceto para os caracteres que devem ser escapados: aspas, solidus reverso e os caracteres de controle (U + 0000 a U + 001F)

caos
fonte
1
Se ler a citação fornecida, você verá que não é necessário escapar todos os caracteres Unicode, apenas alguns caracteres especiais. Mas você deve codificar os resultados (de preferência com utf-8). Portanto, a questão é: "Por que se preocupar em escapar caracteres Unicode normais se você está codificando utf-8".
Schickb
Além disso, uma string codificada em ascii é um subconjunto puro de utf-8. Se eu usar o escape json para todos os caracteres não ascii, o resultado será ascii - e, portanto, utf-8. Várias bibliotecas json (como python simplejson) têm modos para forçar os resultados ASCII. Presumo por uma razão, como talvez a execução em navegadores.
Schickb
Quando você se incomoda em escapar de caracteres Unicode normais é em contextos onde eles são metacaracteres, como strings. (O trecho RFC que citei é sobre strings; desculpe, não estava claro sobre isso.) Você não precisa fazer saídas ASCII o tempo todo; Eu acho que é mais para depurar com navegadores quebrados.
caos
7

Eu estava enfrentando o mesmo problema. Funciona para mim. Por favor, checar isto.

json_encode($array,JSON_UNESCAPED_UNICODE);
Ankit Sewadik
fonte
Deve-se notar que o acima é PHP, já que a questão não é de forma alguma específica do PHP e apenas fala sobre serviços web que também não podem usar PHP (como os mais antigos de nossos leitores ainda
devem se
1

Lendo o json rfc ( http://www.ietf.org/rfc/rfc4627.txt ), fica claro que a codificação preferida é utf-8.

FYI, RFC 4627 não é mais a especificação JSON oficial. Ele ficou obsoleto em 2014 pela RFC 7159 , que foi então obsoleto em 2017 pela RFC 8259 , que é a especificação atual.

RFC 8259 afirma:

8,1 Codificação de Caracteres

O texto JSON trocado entre sistemas que não fazem parte de um ecossistema fechado DEVE ser codificado usando UTF-8 [RFC3629] .

As especificações anteriores de JSON não exigiam o uso de UTF-8 ao transmitir texto JSON. No entanto, a grande maioria das implementações de software baseadas em JSON optou por usar a codificação UTF-8, na medida em que é a única codificação que atinge a interoperabilidade.

As implementações NÃO DEVEM adicionar uma marca de ordem de byte (U + FEFF) ao início de um texto JSON transmitido em rede. No interesse da interoperabilidade, as implementações que analisam textos JSON PODEM ignorar a presença de uma marca de ordem de byte em vez de tratá-la como um erro.

Remy Lebeau
fonte
0

Tive um problema parecido com é char ... Acho que o comentário "é possível que o texto que você está alimentando não seja UTF-8" provavelmente esteja perto da marca aqui. Tenho a sensação de que o agrupamento padrão em minha instância era outra coisa até que percebi e mudei para utf8 ... o problema é que os dados já estavam lá, então não tenho certeza se converteu os dados ou não quando eu os alterei, exibe bem no mysql bancada de trabalho. O resultado final é que o php não codificará os dados em JSON, apenas retornará falso. Não importa qual navegador você usa como servidor que está causando meu problema, o php não analisará os dados para utf8 se este char estiver presente. Como eu disse, não tenho certeza se é devido à conversão do esquema para utf8 depois que os dados estavam presentes ou apenas um bug de php. Neste caso, usejson_encode(utf8_encode($string));

Paul Smith
fonte