Ferramentas para desenvolvedores · Formatador e validador JSON
A ordem das chaves é importante em JSON? Ordenação, igualdade e RFC 8785
· Fundo
JSON padrões validação
A especificação JSON chama objetos não ordenados, mas analisadores e serializadores reais geralmente preservam a ordem, e os esquemas de assinatura dependem disso. Esta postagem desvenda o que a especificação diz, o que as implementações fazem e como a canonização resolve a tensão.
Mesmos dados, bytes diferentes
`{"city":"Oslo","temp":4}` e `{"temp":4,"city":"Oslo"}` contêm os mesmos dois nomes e valores, mas seus bytes de origem são diferentes. O recuo pode adicionar muito mais diferenças textuais sem alterar nenhum dos valores analisados. É por isso que “equal JSON” precisa de uma regra de comparação: você está comparando texto, objetos analisados ou uma representação canônica definida por outro protocolo?
ToolAcre pode remover ruído de espaço em branco formatando ambos os documentos com o mesmo recuo. Ele também pode classificar chaves de objeto recursivamente quando essa opção for selecionada. A classificação altera a ordem dos membros deliberadamente, mas nunca move os elementos do array, porque a posição do array representa os dados. Nem a formatação comum nem esta classificação opcional produzem RFC 8785 JSON canônico, portanto, a saída não deve ser substituída por um formato de assinatura especificado.
O que RFC 8259 diz - um objeto é uma coleção não ordenada de pares name/value, e as implementações podem expor a ordem ou não
RFC 8259 descreve um objeto como uma coleção não ordenada de pares name/value. Portanto, o software que trata a ordem dos membros como o significado de um objeto JSON comum depende de um comportamento fora desse modelo abstrato. As matrizes são ordenadas explicitamente, portanto, `["draft","final"]` não é intercambiável com `["final","draft"]`. A ordem dos objetos e a ordem dos arrays nunca devem ser normalizadas pela mesma regra.
O RFC também observa que as bibliotecas diferem no fato de exporem a ordem dos membros aos chamadores. Esse aviso é suficiente para design portátil: não codifique prioridade ou sequência colocando um membro do objeto antes de outro. Se a sequência for importante, represente-a com uma matriz ou um campo explícito. Um formatador que mostra uma ordem estável é conveniente para humanos, mas não transforma a posição em uma propriedade de nível padrão do objeto.
O que esse formatador realmente faz
Com a classificação desabilitada, ToolAcre analisa o documento e serializa o valor JavaScript resultante. A saída segue o comportamento de enumeração de propriedades JavaScript em vez de preservar o fluxo de token original, byte por byte. A maioria das chaves de string comuns aparecem em uma ordem familiar, enquanto nomes semelhantes a índices inteiros podem ser emitidos antes de outros nomes. A ortografia dos números e as opções de escape também podem ser normalizadas durante a resserialização.
Com a classificação habilitada, o formatador cria novos objetos cujas próprias chaves são colocadas em ordem alfabética em cada objeto aninhado. Para `{"z":{"b":1,"a":2},"items":[{"d":4,"c":3},"x"]}`, os nomes dos objetos tornam-se `items`, `z`; nomes de objetos aninhados também são classificados; e o array ainda contém seu objeto antes de `"x"`. Classificar objetos dentro de um array não significa classificar o array em si.
Quando a ordem dos bytes é importante
A ordem textual é importante sempre que um processo consome bytes exatos em vez do valor abstrato. Um hash de arquivo, chave de cache, assinatura digital ou comparação baseada em linha muda quando os membros são movidos ou os espaços em branco são alterados. Isso não contradiz o modelo de objetos não ordenados; isso significa que o processo circundante escolheu uma representação de bytes como parte de sua entrada. As regras de representação devem então ser explícitas e partilhadas.
Para revisões de rotina, o recuo consistente e a classificação alfabética opcional podem facilitar a visualização das alterações. Para trabalho criptográfico ou de protocolo, “parece estável” não é um contrato. O produtor e o verificador devem usar o algoritmo de canonização exato exigido por seu protocolo antes de fazer hash ou assinar. Se nenhum algoritmo for nomeado, não presuma que a saída de ToolAcre corresponderá a outro serializador em versões, tempos de execução ou valores extremos.
Por que a classificação de chaves não é RFC 8785
RFC 8785 define o esquema de canonização JSON para produzir bytes repetíveis a partir de dados compatíveis. Seu trabalho é mais amplo do que colocar as chaves em ordem alfabética. Ele especifica a classificação determinística de propriedades junto com o comportamento exato de serialização para strings e números e impõe restrições ao modelo de entrada. O recuo bonito não faz parte da saída canônica e a classificação com reconhecimento de localidade não é uma aproximação aceitável.
ToolAcre não faz nenhuma reivindicação de RFC 8785. Sua opção de classificação é um recurso de legibilidade em camadas sobre `JSON.parse` e `JSON.stringify`; ele não valida as pré-condições I-JSON nem substitui as regras de serialização de RFC. Um valor como `1e-7`, uma chave contendo caracteres não ASCII ou uma string de escape pode revelar diferenças entre um formatador classificado casual e um canonicalizador em conformidade. Use uma implementação JCS testada quando JCS for necessário.
Exemplo resolvido: comparar dois documentos de forma justa
Compare `{"meta":{"rev":2,"owner":"Mira"},"steps":["cut","pack"]}` com `{"steps":["cut","pack"],"meta":{"owner":"Mira","rev":2}}`. Formate ambos com dois espaços e classificação desabilitados: os espaços em branco se tornam consistentes, mas as ordens dos membros raiz e aninhados ainda podem ser diferentes. Analise ambos e compare os campos pretendidos para estabelecer equivalência em nível de valor, em vez de declarar o texto bruto igual.
Ative a classificação recursiva de chaves e ambos os exemplos serão renderizados com a mesma ordem de objeto enquanto `steps` permanece `cut` e depois `pack`. Isso é útil para uma comparação humana, mas ainda é a normalização de ToolAcre, não a prova de RFC 8785. Se a segunda matriz fosse `["pack","cut"]`, as chaves de classificação deixariam corretamente essa diferença visível porque alterar a matriz alteraria a sequência representada.
O que isso não cobre
A classificação de chaves não define igualdade profunda para todos os aplicativos. Nomes duplicados são aceitos por `JSON.parse`, que mantém o último valor, portanto a formatação pode apagar evidências de que uma fonte continha repetições. Números inteiros grandes já podem ter perdido precisão no valor JavaScript. Um domínio também pode tratar arrays selecionados como conjuntos, mas ToolAcre não pode inferir essa regra e, portanto, nunca reordena arrays.
O formatador também não compara esquemas, aplica padrões, normaliza Unicode ou decide se duas representações numéricas são aceitáveis para um sistema downstream. Esses são contratos separados. Use a formatação para reduzir o ruído de apresentação, uma comparação estrutural desenvolvida especificamente para igualdade de valores e o canonicalizador especificado para bytes exatos. Misturar essas tarefas sob a palavra “normalizar” cria uma falsa confiança sobre o que foi realmente comparado.
Conclusão: a ordem é insignificante para o modelo e significativa para os bytes
A ordem dos membros do objeto não tem significado no modelo de dados RFC 8259, enquanto a ordem da matriz tem. Os bytes de origem ainda registram a ordem e os espaços em branco, portanto, hashes, assinaturas e diferenças de texto observam distinções que uma comparação orientada a valores pode ignorar. Declare qual camada é importante antes de escolher uma ferramenta: identidade textual, equivalência de valor analisado e identidade canônica definida por protocolo são três questões diferentes.
ToolAcre oferece suporte aos dois primeiros fluxos de trabalho apenas indiretamente: a formatação consistente esclarece as diferenças textuais e a classificação alfabética recursiva por chave de objeto pode tornar as comparações humanas mais silenciosas. Matrizes nunca são classificadas. O resultado não é RFC 8785 JSON canônico e não deve ser assinado como se fosse. Preserve a entrada original quando a evidência lexical for importante, especialmente porque a análise de chaves duplicadas retém apenas o último valor.