Двоичные данные в строке JSON. Что-то лучше, чем Base64 - PullRequest
550 голосов
/ 18 сентября 2009

Формат JSON изначально не поддерживает двоичные данные. Двоичные данные должны быть экранированы, чтобы их можно было поместить в строковый элемент (т. Е. Ноль или более символов Unicode в двойных кавычках с использованием обратной косой черты) в JSON.

Очевидный способ избежать двоичных данных - использовать Base64. Тем не менее, Base64 имеет большие накладные расходы на обработку. Также он расширяет 3 байта в 4 символа, что приводит к увеличению размера данных примерно на 33%.

Одним из вариантов использования этого является черновой вариант версии 0.8 спецификации API облачного хранилища CDMI *1008*. Вы создаете объекты данных через REST-Webservice, используя JSON, например,

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=",
}

Существуют ли лучшие способы и стандартные методы для кодирования двоичных данных в строки JSON?

Ответы [ 16 ]

2 голосов
/ 12 апреля 2016

Просто чтобы добавить ресурс и сложность в обсуждение. Поскольку вы выполняете PUT / POST и PATCH для хранения новых ресурсов и их изменения, следует помнить, что передача контента является точным представлением контента, который хранится и который получен с помощью операции GET.

Многочастное сообщение часто используется как спаситель, но по причине простоты и для более сложных задач я предпочитаю выдавать контент целиком. Это самоочевидно и просто.

И, конечно, JSON - это что-то серьезное, но в конце концов, сам JSON многословен. А накладные расходы на отображение в BASE64 - это путь к малым.

Для правильного использования многокомпонентных сообщений необходимо либо демонтировать объект для отправки, использовать путь свойства в качестве имени параметра для автоматического комбинирования, либо создать другой протокол / формат для простого выражения полезной нагрузки.

Также нравится подход BSON, он не так широко и легко поддерживается, как хотелось бы.

По сути, мы просто что-то здесь упускаем, но встраивание двоичных данных в base64 хорошо известно, и есть путь, если вы действительно не определили необходимость выполнения реальной двоичной передачи (что вряд ли имеет место).

0 голосов
/ 03 ноября 2018

Я копаю немного больше (во время реализации base128 ) и выставляю это , когда мы отправляем символы с кодами ascii больше 128, а браузер (chrome) фактически отправляет ДВА символа ( байт) вместо одного: (. Причина в том, что JSON по умолчанию использует символы utf8, для которых символы с кодами ascii выше 127 кодируются двумя байтами, что упоминалось в ответе chmike . Я сделал тест в таким образом: введите chrome url bar chrome: // net-export / , выберите «Включить необработанные байты», начните захват, отправляйте POST-запросы (используя фрагмент внизу), прекратите захват и сохраните файл json с необработанными данными запросов. Затем мы смотрим внутрь этого файла JSON:

  • Мы можем найти наш запрос base64, найдя строку 4142434445464748494a4b4c4d4e это шестнадцатеричное кодирование ABCDEFGHIJKLMN, и мы увидим, что "byte_count": 639 для него.
  • Мы можем найти наш запрос выше 127, найдя строку C2BCC2BDC380C381C382C383C384C385C386C387C388C389C38AC38B это шестнадцатеричные коды символов запроса ¼½ÀÁÂÃÄÅÆÇÈÉÊË (однако шестнадцатеричные коды этих символов ascii равны c1c2c3c4c5c6c7c8c9cacbcccdce). "byte_count": 703, поэтому он на 64 байта длиннее, чем запрос base64, потому что символы с кодами ascii выше 127 кодируются на 2 байта в запросе: (

Так что на самом деле у нас нет прибыли от отправки символов с кодами> 127 :(. Для строк base64 мы не наблюдаем такого негативного поведения (вероятно, и для base85 - я не проверяю это) - однако может быть какое-то решение для этого проблема заключается в отправке данных в двоичной части POST multipart / form-data, описанной в Ælex answer (однако обычно в этом случае нам вообще не нужно использовать какое-либо базовое кодирование ...).

Альтернативный подход может основываться на отображении двухбайтовой части данных в один действительный символ utf8 с помощью кода, использующего что-то вроде base65280 / base65k , но, вероятно, он будет менее эффективным, чем base64 из-за спецификации utf8 ...

function postBase64() {
  let formData = new FormData();
  let req = new XMLHttpRequest();

  formData.append("base64ch", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
  req.open("POST", '/testBase64ch');
  req.send(formData);
}


function postAbove127() {
  let formData = new FormData();
  let req = new XMLHttpRequest();

  formData.append("above127", "¼½ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüý");
  req.open("POST", '/testAbove127');
  req.send(formData);
}
<button onclick=postBase64()>POST base64 chars</button>
<button onclick=postAbove127()>POST chars with codes>127</button>
0 голосов
/ 25 июня 2018

Если вы используете Node, я думаю, что самый эффективный и простой способ - это конвертировать в UTF16 с помощью:

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

Вы можете получить свои данные по:

Buffer.from(s, 'utf16le');
0 голосов
/ 11 февраля 2014

Мое решение сейчас, XHR2 использует ArrayBuffer. ArrayBuffer в виде двоичной последовательности содержит многокомпонентный контент, видео, аудио, графику, текст и т. Д. С несколькими типами контента. Все в одном ответе.

В современном браузере, имеющем DataView, StringView и Blob для разных компонентов. Смотрите также: http://rolfrost.de/video.html для более подробной информации.

0 голосов
/ 22 июня 2013

См .: http://snia.org/sites/default/files/Multi-part%20MIME%20Extension%20v1.0g.pdf

В нем описан способ передачи двоичных данных между клиентом и сервером CDMI с помощью операций «тип содержимого CDMI» без необходимости преобразования двоичных данных в base64.

Если вы можете использовать операцию «Тип содержимого не-CDMI», то идеально для передачи «данных» в / из объекта. Затем метаданные затем могут быть добавлены / извлечены в / из объекта как последующая операция «тип содержимого CDMI».

0 голосов
/ 02 апреля 2012

Тип данных действительно касается. Я проверил различные сценарии отправки полезных данных из ресурса RESTful. Для кодирования я использовал Base64 (Apache) и для сжатия GZIP (java.utils.zip. *). Полезная нагрузка содержит информацию о фильме, изображение и аудиофайл. Я сжал и закодировал изображения и аудиофайлы, что резко ухудшило производительность. Кодирование до сжатия получилось хорошо. Изображение и аудиоконтент были отправлены в виде закодированных и сжатых байтов [].

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...