Données binarys dans la chaîne JSON. Quelque chose de mieux que Base64

Le format JSON en mode natif ne prend pas en charge les données binarys. Les données binarys doivent être échappées pour pouvoir être placées dans un élément de chaîne (c.-à-d. Zéro ou plusieurs caractères Unicode entre guillemets en utilisant des échappements de barres obliques inverses) dans JSON.

Une méthode évidente pour échapper à des données binarys consiste à utiliser Base64. Cependant, Base64 a une surcharge de traitement élevée. Il étend également 3 octets en 4 caractères, ce qui conduit à une augmentation de la taille des données d’environ 33%.

Un exemple d’utilisation est le brouillon v0.8 de la spécification de l’API de stockage en nuage CDMI . Vous créez des objects de données via un service Web REST en utilisant JSON, par exemple

PUT /MyContainer/BinaryObject HTTP/1.1 Host: cloud.example.com Accept: application/vnd.org.snia.cdmi.dataobject+json Content-Type: application/vnd.org.snia.cdmi.dataobject+json X-CDMI-Specification-Version: 1.0 { "mimetype" : "application/octet-stream", "metadata" : [ ], "value" : "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=", } 

Existe-t-il de meilleurs moyens et méthodes standard pour encoder des données binarys en chaînes JSON?

Il y a 94 caractères Unicode qui peuvent être représentés sous la forme d’un octet selon la spécification JSON (si votre JSON est transmis en UTF-8). Dans cet esprit, je pense que le mieux que vous puissiez faire dans le domaine de l’espace est base85, qui représente quatre octets en cinq caractères. Cependant, il ne s’agit que d’une amélioration de 7% par rapport à base64, c’est plus coûteux à calculer, et les implémentations sont moins courantes que pour la base64, donc ce n’est probablement pas une victoire.

Vous pouvez aussi simplement mapper chaque octet d’entrée sur le caractère correspondant dans U + 0000-U + 00FF, puis faire le codage minimum requirejs par la norme JSON pour transmettre ces caractères; L’avantage ici est que le décodage requirejs est nul au-delà des fonctions intégrées, mais l’efficacité de l’espace est mauvaise – une expansion de 105% (si tous les octets sont également probables) contre 25% pour la base85 ou 33% pour la base64.

Jugement final: la base64 gagne, à mon avis, au motif que c’est commun, facile et pas assez grave pour justifier un remplacement.

Je sais que cette question remonte à presque 6 ans, mais je rencontre le même problème et je pensais partager une solution: multipart / form-data.

En envoyant un formulaire en plusieurs parties, vous envoyez d’abord en tant que chaîne vos métadonnées JSON , puis envoyez-les séparément en tant que binarys bruts (images, wavs, etc.) indexés par le nom Content-Disposition .

Voici un bon tutoriel sur la façon de faire cela dans obj-c, et voici un article de blog qui explique comment partitionner les données de chaîne avec les limites du formulaire et les séparer des données binarys.

Le seul changement que vous devez vraiment faire est côté serveur; vous devrez capturer vos métadonnées qui doivent faire référence aux données binarys POST de manière appropriée (en utilisant une limite Content-Disposition).

Certes, cela nécessite un travail supplémentaire du côté du serveur, mais si vous envoyez de nombreuses images ou de grandes images, cela en vaut la peine. Combinez cela avec la compression gzip si vous voulez.

IMHO envoyer des données encodées en base64 est un hack; le RFC multipart / form-data a été créé pour des problèmes tels que: l’envoi de données binarys en combinaison avec du texte ou des métadonnées.

BSON (Binary JSON) peut fonctionner pour vous. http://en.wikipedia.org/wiki/BSON

Edit: FYI la bibliothèque .NET json.net supporte la lecture et l’écriture de bson si vous recherchez un côté serveur C #.

Le problème avec UTF-8 est que ce n’est pas le codage le plus efficace en termes d’espace. En outre, certaines séquences d’octets binarys aléatoires sont des codages UTF-8 non valides. Donc, vous ne pouvez pas simplement interpréter une séquence d’octets binarys aléatoires comme des données UTF-8, car il s’agira d’un codage UTF-8 non valide. L’avantage de cette contrainte sur le codage UTF-8 est qu’elle rend robuste et possible le repérage et la fin des caractères multi-octets, quel que soit l’octet que nous commençons à regarder.

Par conséquent, si le codage d’une valeur d’octet dans la plage [0..127] nécessiterait un seul octet dans le codage UTF-8, le codage d’une valeur d’octet dans la plage [128..255] nécessiterait 2 octets! Pire que ça. Dans JSON, les caractères de contrôle “et \ ne sont pas autorisés à apparaître dans une chaîne. Par conséquent, les données binarys nécessiteraient une transformation pour être correctement codées.

Laisse voir. Si nous supposons des valeurs d’octets aléatoires uniformément dissortingbuées dans nos données binarys, alors en moyenne, la moitié des octets serait codée dans un octet et l’autre moitié dans deux octets. Les données binarys encodées en UTF-8 auraient 150% de la taille initiale.

L’encodage Base64 ne croît que jusqu’à 133% de la taille initiale. L’encodage Base64 est donc plus efficace.

Qu’en est-il de l’utilisation d’un autre encodage de base? En UTF-8, l’encodage des 128 valeurs ASCII est le plus efficace en termes d’espace. En 8 bits, vous pouvez stocker 7 bits. Donc, si nous coupons les données binarys en blocs de 7 bits pour les stocker dans chaque octet d’une chaîne codée en UTF-8, les données codées augmenteront seulement jusqu’à 114% de la taille initiale. Mieux que Base64. Malheureusement, nous ne pouvons pas utiliser cette astuce car JSON n’autorise pas certains caractères ASCII. Les 33 caractères de contrôle de ASCII ([0..31] et 127) et le “et \ doivent être exclus. Cela ne nous laisse que 128-35 = 93 caractères.

Donc, en théorie, nous pourrions définir un codage Base93 qui ferait passer la taille codée à 8 / log2 (93) = 8 * log10 (2) / log10 (93) = 122%. Mais un encodage Base93 ne serait pas aussi pratique qu’un encodage Base64. Base64 nécessite de couper la séquence d’octets d’entrée en blocs de 6 bits pour lesquels un fonctionnement simple au niveau du bit fonctionne bien. À part 133%, ce n’est pas beaucoup plus que 122%.

C’est pourquoi je suis venu à la conclusion commune que Base64 est en effet le meilleur choix pour encoder des données binarys en JSON. Ma réponse le justifie. Je suis d’accord pour dire que ce n’est pas très intéressant du sharepoint vue de la performance, mais considérez également l’avantage d’utiliser JSON avec sa représentation de chaîne lisible par l’homme, facile à manipuler dans tous les langages de programmation.

Si les performances sont critiques, un encodage binary pur doit être considéré comme un remplacement de JSON. Mais avec JSON, ma conclusion est que Base64 est le meilleur.

Si vous rencontrez des problèmes de bande passante, essayez d’abord de compresser les données côté client, puis base64-it.

Un bon exemple de cette magie est à http://jszip.stuartk.co.uk/ et plus de discussion à ce sujet est à la mise en œuvre JavaScript de Gzip

yEnc pourrait fonctionner pour vous:

http://en.wikipedia.org/wiki/Yenc

Format de sourire

Il est très rapide d’encoder, de décoder et de compacter

Comparaison de vitesse (basée sur Java mais néanmoins significative): https://github.com/eishay/jvm-serializers/wiki/

C’est aussi une extension de JSON qui vous permet d’ignorer l’encodage base64 pour les tableaux d’octets

Les chaînes codées Smile peuvent être compressées lorsque l’espace est critique

Bien qu’il soit vrai que base64 a un taux d’expansion de ~ 33%, il n’est pas forcément vrai que la surcharge de traitement est bien plus importante que cela: cela dépend vraiment de la bibliothèque / du toolkit JSON que vous utilisez. L’encodage et le décodage sont des opérations simples et peuvent même être optimisés avec le codage des caractères (JSON ne supportant que les UTF-8/16/32) – les caractères base64 sont toujours à un octet pour les entrées de chaînes JSON. Par exemple, sur la plate-forme Java, il existe des bibliothèques qui peuvent faire le travail assez efficacement, de sorte que la surcharge est principalement due à la taille étendue.

Je suis d’accord avec deux réponses précédentes:

  • base64 est simple, standard utilisé, il est donc peu probable de trouver quelque chose de mieux spécifique à utiliser avec JSON (base-85 est utilisé par postscript, etc., mais les avantages sont au mieux marginaux quand on y pense)
  • la compression avant l’encodage (et après le décodage) peut avoir beaucoup de sens, selon les données que vous utilisez

Étant donné que vous recherchez la possibilité de transférer des données binarys dans un format ssortingctement textuel et très limité, je pense que la surcharge de Base64 est minime par rapport à la commodité que vous attendez avec JSON. Si la puissance de traitement et le débit sont une préoccupation, vous devrez probablement revoir vos formats de fichiers.

( Modifier 7 ans plus tard: Google Gears est parti. Ignorer cette réponse.)

L’équipe Google Gears a rencontré le problème de l’absence de données binarys et a tenté de le résoudre:

API Blob

JavaScript a un type de données intégré pour les chaînes de texte, mais rien pour les données binarys. L’object Blob tente de résoudre cette limitation.

Peut-être que vous pouvez tisser cela en quelque sorte.

Juste pour append le sharepoint vue de la ressource et de la complexité à la discussion. Depuis que PUT / POST et PATCH sont stockés pour stocker de nouvelles ressources et les modifier, il ne faut pas oublier que le transfert de contenu est une représentation exacte du contenu stocké et reçu lors d’une opération GET.

Un message en plusieurs parties est souvent utilisé comme un sauveur mais pour des raisons de simplicité et pour des tâches plus complexes, je préfère l’idée de donner le contenu dans son ensemble. C’est auto-expliquant et c’est simple.

Et oui, JSON est quelque chose de paralysant mais au final JSON lui-même est verbeux. Et la surcharge de la mise en correspondance avec BASE64 est un moyen de réduire les coûts.

En utilisant correctement les messages en plusieurs parties, il faut soit démonter l’object à envoyer, utiliser un chemin de propriété comme nom de paramètre pour la combinaison automatique, soit créer un autre protocole / format pour exprimer la charge utile.

Appréciant également l’approche de BSON, ce n’est pas aussi largement et facilement supporté que l’on voudrait qu’il soit.

Fondamentalement, nous manquons quelque chose ici, mais l’intégration des données binarys comme base64 est bien établie et le chemin à parcourir, à moins que vous ayez vraiment identifié le besoin de faire le vrai transfert binary (ce qui est rarement le cas).

Le type de données concerne vraiment. J’ai testé différents scénarios sur l’envoi de la charge utile à partir d’une ressource RESTful. Pour l’encodage, j’ai utilisé Base64 (Apache) et pour la compression GZIP (java.utils.zip. *). La charge utile contient des informations sur le film, une image et un fichier audio. J’ai compressé et encodé les fichiers image et audio, ce qui a considérablement dégradé les performances. L’encodage avant la compression s’est bien passé. Le contenu image et audio a été envoyé sous forme d’octets codés et compressés [].

Se référer à: http://snia.org/sites/default/files/Multi-part%20MIME%20Extension%20v1.0g.pdf

Il décrit un moyen de transférer des données binarys entre un client CDMI et un serveur en utilisant les opérations de type de contenu CDMI sans nécessiter de conversion en base64 des données binarys.

Si vous pouvez utiliser l’opération “Type de contenu non-CDMI”, il est idéal de transférer des “données” vers / depuis un object. Les métadonnées peuvent ensuite être ajoutées / extraites de / à partir de l’object en tant qu’opération «type de contenu CDMI» ultérieure.

Si vous utilisez Node, je pense que le moyen le plus efficace et le plus simple est de convertir en UTF16 avec:

 Buffer.from(data).toSsortingng('utf16le'); 

Vous pouvez récupérer vos données en:

 Buffer.from(s, 'utf16le'); 

Ma solution maintenant, XHR2 utilise ArrayBuffer. ArrayBuffer en tant que séquence binary contient du contenu en plusieurs parties, de la vidéo, de l’audio, du graphique, du texte, etc., avec plusieurs types de contenu. All in One Response.

Dans le navigateur moderne, avec DataView, SsortingngView et Blob pour différents composants. Voir aussi: http://rolfrost.de/video.html pour plus de détails.