При работе с платформой 1С:Предприятие часто возникает задача передачи больших объемов данных между сервером и клиентским приложением, особенно когда речь идет о мобильных приложениях. Объект ХранилищеЗначений является удобным инструментом для временного или постоянного хранения произвольных данных, включая бинарные. Однако его прямая передача по сети требует преобразования в формат, пригодный для HTTP-транспорта, и оптимального сжатия. Рассмотрим подробнее, как преобразовать ХранилищеЗначений в двоичные данные, передать их в мобильное приложение и обеспечить их корректную обработку, избегая при этом создания временных файлов на диске.
Передача данных в мобильные приложения имеет свои нюансы. Мобильные каналы связи могут быть менее стабильными и быстрыми, чем стационарные, поэтому оптимизация объема передаваемых данных становится критически важной. Кроме того, функциональность мобильной платформы, хотя и расширяется с каждой новой версией, имеет свои ограничения по сравнению с полноценным десктопным клиентом.
Основной вопрос, который часто возникает: как получить сжатые двоичные данные из ХранилищеЗначений и передать их в формате JSON через HTTP-сервис так, чтобы мобильное приложение могло их корректно принять и обработать? При этом важно избежать создания промежуточных файлов на диске, работая полностью в оперативной памяти.
Одним из наиболее простых и доступных способов передачи объекта ХранилищеЗначений является его сериализация в формат XML. Платформа 1С:Предприятие при сериализации ХранилищаЗначений автоматически кодирует его содержимое (в том числе двоичные данные) с использованием алгоритма Base64. Это означает, что вы можете получить строковое представление вашего хранилища, которое затем легко встраивается в JSON-ответ и передается по HTTP.
Разберем по шагам, как это работает:
ХранилищаЗначений на сервере:
Сначала вам нужно создать объект ХранилищеЗначений и поместить в него необходимые данные. Если вы уже имеете ДвоичныеДанные, можете сразу указать желаемую степень сжатия при создании хранилища.
// Предположим, у нас есть какие-то ДвоичныеДанные
// Например, прочитанные из файла или сформированные программно
// ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПолноеИмяФайла);
// Или, например, строка, которую мы хотим сохранить как двоичные данные
СтрокаДляХранения = "Это строка с данными для мобильного приложения.";
ДвоичныеДанныеСтроки = Новый ДвоичныеДанные(СтрокаДляХранения, КодировкаТекста.UTF8);
// Создаем ХранилищеЗначений с максимальным сжатием
Хранилище = Новый ХранилищеЗначения(ДвоичныеДанныеСтроки, Новый СжатиеДанных(9));
// Или без явного указания сжатия, если данные уже пожаты или сжатие не требуется
// Хранилище = Новый ХранилищеЗначения(ДвоичныеДанныеСтроки);
ХранилищаЗначений в XML-строку на сервере:
Для преобразования объекта ХранилищеЗначений в строку, пригодную для передачи, используйте методы сериализации 1С. Обычно это делается через объект ЗаписьXML или СериализаторXDTO.
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку(); // Записываем в строку
ЗаписьXML.ЗаписатьНачалоДокумента();
// Записываем ХранилищеЗначений как корневой элемент
ЗаписатьXML(ЗаписьXML, Хранилище);
СтрокаXMLХранилища = ЗаписьXML.Закрыть();
// Теперь СтрокаXMLХранилища содержит Base64-кодированное представление данных
// Мы можем добавить эту строку в JSON-ответ HTTP-сервиса
// Например, ОтветJSON.Вставить("Данные", СтрокаXMLХранилища);
Эта строка СтрокаXMLХранилища будет содержать XML-представление объекта ХранилищеЗначений, внутри которого бинарные данные будут закодированы в Base64. Вы можете передать эту строку как часть JSON-ответа вашего HTTP-сервиса.
В мобильном приложении вы принимаете эту XML-строку (из JSON-ответа) и десериализуете ее обратно в объект ХранилищеЗначений. Затем извлекаете исходные данные.
// Предположим, СтрокаXMLХранилища была получена из JSON-ответа
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(СтрокаXMLХранилища);
ХранилищеПолученное = ПрочитатьXML(ЧтениеXML);
// Извлекаем исходные данные из хранилища
ИсходныеДанные = ХранилищеПолученное.Получить();
// Если изначально это были ДвоичныеДанныеСтроки
// СтрокаОбратно = ИсходныеДанные.ПолучитьСтроку();
// Сообщить("Полученная строка: " + СтрокаОбратно);
Важно отметить: Хотя в документации (СП) 1С иногда встречаются противоречия относительно доступности ХранилищеЗначений в мобильных приложениях, на практике (например, в релизах 18.х мобильной платформы) объект ХранилищеЗначений и его конструкторы продолжают успешно работать в мобильном приложении. Это позволяет беспрепятственно использовать данный подход.
Преимущества этого метода:
ХранилищаЗначений.Недостатки:
ХранилищеЗначений не было создано с явным сжатием (Новый СжатиеДанных(9)), XML-представление может быть объемным.Для получения максимального контроля над форматом и степенью сжатия, а также для избежания "хвостов" 1С-ной сериализации, мы можем использовать явное создание ZIP-архива. Этот подход включает в себя использование объектов ПотокВПамяти и ЗаписьZIP на сервере, а затем ЧтениеZIP на мобильном приложении. Объект ПотокВПамяти позволяет работать с данными непосредственно в оперативной памяти, что соответствует требованию "без создания файлов на диске".
Рассмотрим по шагам:
На стороне сервера мы будем использовать ПотокВПамяти для создания ZIP-архива, а затем получим из него ДвоичныеДанные, которые затем кодируем в Base64 для передачи.
// 1. Извлекаем ДвоичныеДанные из ХранилищаЗначений.
// Предположим, у нас есть Хранилище, которое мы хотим передать.
// Если в Хранилище были ДвоичныеДанные, Получить() вернет их.
// Если в Хранилище был другой тип, то его можно предварительно сериализовать
// Например, в JSON-строку, а потом преобразовать в ДвоичныеДанные.
// Для примера, возьмем исходные ДвоичныеДанные
СтрокаДляХранения = "Это строка с данными, которую мы хотим сжать в ZIP и передать.";
ДвоичныеДанныеИсходные = Новый ДвоичныеДанные(СтрокаДляХранения, КодировкаТекста.UTF8);
// Или, если в ХранилищеЗначений уже есть ДвоичныеДанные:
// ДвоичныеДанныеИсходные = МоеХранилищеЗначений.Получить();
// 2. Создаем ПотокВПамяти для записи ZIP-архива.
ПотокПамяти = Новый ПотокВПамяти;
// 3. Создаем объект ЗаписьZIP для записи в ПотокВПамяти.
// Истина вторым параметром указывает на необходимость сжатия.
ЗаписьZIP = Новый ЗаписьZIP(ПотокПамяти, Истина, КодировкаТекста.UTF8);
// 4. Добавляем исходные ДвоичныеДанные в ZIP-архив под определенным именем.
// Имя файла внутри архива ('data.bin') может быть любым.
ЗаписьZIP.Добавить(ДвоичныеДанныеИсходные, "data.bin");
// Если нужно добавить несколько файлов или объектов, повторяем ЗаписьZIP.Добавить()
// Например, сериализуем другой объект в JSON, потом в ДвоичныеДанные и добавляем в ZIP
// ДругойОбъект = "Еще какие-то данные";
// ЗаписьJSON = Новый ЗаписьJSON;
// ЗаписьJSON.УстановитьСтроку();
// ЗаписатьJSON(ЗаписьJSON, ДругойОбъект);
// ДвоичныеДанныеДругогоОбъекта = Новый ДвоичныеДанные(ЗаписьJSON.Закрыть(), КодировкаТекста.UTF8);
// ЗаписьZIP.Добавить(ДвоичныеДанныеДругогоОбъекта, "another_object.json");
// 5. Завершаем запись в ZIP и закрываем объекты.
ЗаписьZIP.ЗакончитьДобавление();
ЗаписьZIP.Закрыть();
// 6. Получаем сжатые двоичные данные из ПотокВПамяти.
ДвоичныеДанныеZIP = ПотокПамяти.ЗакрытьИПолучитьДвоичныеДанные();
// 7. Кодируем полученные ДвоичныеДанные в Base64-строку для передачи в JSON.
СтрокаBase64ZIP = Base64Строка(ДвоичныеДанныеZIP);
// Теперь СтрокаBase64ZIP может быть включена в JSON-ответ HTTP-сервиса.
// Например, ОтветJSON.Вставить("ДанныеZIP", СтрокаBase64ZIP);
Методы Base64Строка() и Base64Значение() доступны как на сервере, так и на клиенте (включая мобильное приложение), что делает их идеальными для обмена бинарными данными.
Исторически работа с ZIP-архивами в мобильных приложениях 1С была затруднена или требовала обходных путей. Однако, это КРИТИЧЕСКИ ВАЖНОЕ ДОПОЛНЕНИЕ: начиная с версии 8.3.21 мобильной платформы 1С:Предприятие, реализована полная поддержка работы с ZIP-файлами. Вся функциональность по упаковке и распаковке ZIP-архивов доступна непосредственно в мобильном клиенте и мобильной платформе без использования сторонних инструментов. Это означает, что проблема, упомянутая в сообщении 10 форума, теперь полностью решена.
Теперь вы можете распаковать ZIP-архив в мобильном приложении следующим образом:
// 1. Получаем Base64-строку из JSON-ответа HTTP-сервиса.
// СтрокаBase64ZIP = ... // из JSON-ответа
// 2. Декодируем Base64-строку обратно в ДвоичныеДанные.
ДвоичныеДанныеZIP = Base64Значение(СтрокаBase64ZIP);
// 3. Создаем ПотокВПамяти из полученных ДвоичныхДанных ZIP-архива.
ПотокПамятиДляЧтения = Новый ПотокВПамяти(ДвоичныеДанныеZIP);
// 4. Создаем объект ЧтениеZIP для чтения из ПотокВПамяти.
ЧтениеZIP = Новый ЧтениеZIP(ПотокПамятиДляЧтения, КодировкаТекста.UTF8);
// 5. Проходим по элементам архива и извлекаем нужные данные.
Для Каждого ЭлементАрхива Из ЧтениеZIP.Элементы Цикл
// Если мы знаем имя файла внутри архива
Если ЭлементАрхива.Имя = "data.bin" Тогда
// Читаем двоичные данные конкретного элемента
ДвоичныеДанныеИзАрхива = ЧтениеZIP.Прочитать(ЭлементАрхива);
// Теперь у нас есть исходные ДвоичныеДанные, которые были сжаты на сервере.
// Их можно использовать дальше: например, преобразовать обратно в строку
СтрокаОбратно = ДвоичныеДанныеИзАрхива.ПолучитьСтроку(КодировкаТекста.UTF8);
Сообщить("Извлеченная строка из ZIP: " + СтрокаОбратно);
// Или сохранить в новое ХранилищеЗначений, если это необходимо
// ХранилищеОбратно = Новый ХранилищеЗначений(ДвоичныеДанныеИзАрхива);
Прервать; // Если нам нужен только один файл из архива
КонецЕсли;
КонецЦикла;
// 6. Закрываем объекты чтения.
ЧтениеZIP.Закрыть();
ПотокПамятиДляЧтения.Закрыть();
Преимущества этого метода:
Недостатки:
ПотокВПамяти, ЗаписьZIP/ЧтениеZIP, ДвоичныеДанные, Base64Строка/Base64Значение).Помимо явного сжатия данных на уровне 1С, существует возможность использования прозрачного сжатия на уровне веб-сервера (например, IIS, Apache, Nginx) с использованием алгоритма gzip. Этот метод работает на транспортном уровне HTTP и является полностью прозрачным для клиента, если он поддерживает gzip (а большинство современных браузеров и мобильных клиентов его поддерживают).
Разберем, как это работает:
На веб-сервере, который обслуживает HTTP-сервис 1С, включается модуль сжатия. При настроенном сжатии веб-сервер автоматически сжимает HTTP-ответы, если клиент в запросе указывает поддержку сжатия (через заголовок Accept-Encoding: gzip, deflate).
Клиентское приложение (в данном случае мобильное приложение 1С) автоматически отправляет заголовок Accept-Encoding. Если веб-сервер настроен на сжатие и получает такой заголовок, он сжимает ответ и добавляет заголовок Content-Encoding: gzip. Мобильное приложение получает сжатый ответ и автоматически его распаковывает, предоставляя приложению уже распакованные данные.
Преимущества этого метода:
Недостатки:
Accept-Encoding в запросе клиента.Учитывая опасения автора относительно отсутствия контроля и гарантий при использовании прозрачного сжатия веб-сервером, мы рекомендуем сосредоточиться на методах, которые предоставляют явный контроль: сериализация в XML/Base64 или явное сжатие в ZIP/Base64.
При выборе метода передачи данных мы рекомендуем учитывать следующие моменты:
ПотокВПамяти и Base64Строка будет предпочтительным. Благодаря поддержке ZIP в мобильной платформе 8.3.21+, это стало наиболее универсальным и контролируемым решением.ДвоичныеДанные в сочетании с Base64Строка() и Base64Значение() является очень гибким подходом, так как ДвоичныеДанные доступны на всех видах клиентов (тонкий клиент, веб-клиент, мобильный клиент и мобильное приложение) и на сервере. Это позволяет свободно передавать бинарные данные между любыми точками системы.Итоговый вывод: Для преобразования ХранилищаЗначений в двоичные данные и их эффективной передачи в мобильное приложение 1С через HTTP-сервис, когда требуется полный контроль и гарантии, наиболее надежным и рекомендуемым решением является явное сжатие данных в ZIP-архив с использованием объекта ПотокВПамяти на сервере, кодирование получившихся ДвоичныеДанныеZIP в Base64-строку для передачи в JSON, и последующая распаковка и декодирование в мобильном приложении 1С с использованием объектов ЧтениеZIP и Base64Значение(). Этот подход обеспечивает высокую степень сжатия, отсутствие лишних метаданных и полную функциональность на мобильной платформе 1С:Предприятие версии 8.3.21 и выше.