Как преобразовать объект 1С "ХранилищеЗначений" в двоичные данные и эффективно передать их в мобильное приложение через HTTP-сервис?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с платформой 1С:Предприятие часто возникает задача передачи больших объемов данных между сервером и клиентским приложением, особенно когда речь идет о мобильных приложениях. Объект ХранилищеЗначений является удобным инструментом для временного или постоянного хранения произвольных данных, включая бинарные. Однако его прямая передача по сети требует преобразования в формат, пригодный для HTTP-транспорта, и оптимального сжатия. Рассмотрим подробнее, как преобразовать ХранилищеЗначений в двоичные данные, передать их в мобильное приложение и обеспечить их корректную обработку, избегая при этом создания временных файлов на диске.

Особенности передачи данных в мобильные приложения 1С

Передача данных в мобильные приложения имеет свои нюансы. Мобильные каналы связи могут быть менее стабильными и быстрыми, чем стационарные, поэтому оптимизация объема передаваемых данных становится критически важной. Кроме того, функциональность мобильной платформы, хотя и расширяется с каждой новой версией, имеет свои ограничения по сравнению с полноценным десктопным клиентом.

Основной вопрос, который часто возникает: как получить сжатые двоичные данные из ХранилищеЗначений и передать их в формате JSON через HTTP-сервис так, чтобы мобильное приложение могло их корректно принять и обработать? При этом важно избежать создания промежуточных файлов на диске, работая полностью в оперативной памяти.

Метод 1: Сериализация "ХранилищаЗначений" в XML с кодированием Base64

Одним из наиболее простых и доступных способов передачи объекта ХранилищеЗначений является его сериализация в формат XML. Платформа 1С:Предприятие при сериализации ХранилищаЗначений автоматически кодирует его содержимое (в том числе двоичные данные) с использованием алгоритма Base64. Это означает, что вы можете получить строковое представление вашего хранилища, которое затем легко встраивается в JSON-ответ и передается по HTTP.

Разберем по шагам, как это работает:

  1. Создание и заполнение ХранилищаЗначений на сервере:

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

    
    // Предположим, у нас есть какие-то ДвоичныеДанные
    // Например, прочитанные из файла или сформированные программно
    // ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПолноеИмяФайла);
            
    // Или, например, строка, которую мы хотим сохранить как двоичные данные
    СтрокаДляХранения = "Это строка с данными для мобильного приложения.";
    ДвоичныеДанныеСтроки = Новый ДвоичныеДанные(СтрокаДляХранения, КодировкаТекста.UTF8);
    
    // Создаем ХранилищеЗначений с максимальным сжатием
    Хранилище = Новый ХранилищеЗначения(ДвоичныеДанныеСтроки, Новый СжатиеДанных(9)); 
    // Или без явного указания сжатия, если данные уже пожаты или сжатие не требуется
    // Хранилище = Новый ХранилищеЗначения(ДвоичныеДанныеСтроки);
    
  2. Сериализация ХранилищаЗначений в XML-строку на сервере:

    Для преобразования объекта ХранилищеЗначений в строку, пригодную для передачи, используйте методы сериализации 1С. Обычно это делается через объект ЗаписьXML или СериализаторXDTO.

    
    ЗаписьXML = Новый ЗаписьXML;
    ЗаписьXML.УстановитьСтроку(); // Записываем в строку
    ЗаписьXML.ЗаписатьНачалоДокумента();
            
    // Записываем ХранилищеЗначений как корневой элемент
    ЗаписатьXML(ЗаписьXML, Хранилище); 
            
    СтрокаXMLХранилища = ЗаписьXML.Закрыть();
    // Теперь СтрокаXMLХранилища содержит Base64-кодированное представление данных
    // Мы можем добавить эту строку в JSON-ответ HTTP-сервиса
    // Например, ОтветJSON.Вставить("Данные", СтрокаXMLХранилища);
    

    Эта строка СтрокаXMLХранилища будет содержать XML-представление объекта ХранилищеЗначений, внутри которого бинарные данные будут закодированы в Base64. Вы можете передать эту строку как часть JSON-ответа вашего HTTP-сервиса.

  3. Десериализация и извлечение данных в мобильном приложении:

    В мобильном приложении вы принимаете эту XML-строку (из JSON-ответа) и десериализуете ее обратно в объект ХранилищеЗначений. Затем извлекаете исходные данные.

    
    // Предположим, СтрокаXMLХранилища была получена из JSON-ответа
            
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.УстановитьСтроку(СтрокаXMLХранилища);
            
    ХранилищеПолученное = ПрочитатьXML(ЧтениеXML);
            
    // Извлекаем исходные данные из хранилища
    ИсходныеДанные = ХранилищеПолученное.Получить();
            
    // Если изначально это были ДвоичныеДанныеСтроки
    // СтрокаОбратно = ИсходныеДанные.ПолучитьСтроку();
    // Сообщить("Полученная строка: " + СтрокаОбратно);
    

    Важно отметить: Хотя в документации (СП) 1С иногда встречаются противоречия относительно доступности ХранилищеЗначений в мобильных приложениях, на практике (например, в релизах 18.х мобильной платформы) объект ХранилищеЗначений и его конструкторы продолжают успешно работать в мобильном приложении. Это позволяет беспрепятственно использовать данный подход.

Преимущества этого метода:

Недостатки:

Метод 2: Явное сжатие в ZIP-архив с использованием "ПотокВПамяти"

Для получения максимального контроля над форматом и степенью сжатия, а также для избежания "хвостов" 1С-ной сериализации, мы можем использовать явное создание ZIP-архива. Этот подход включает в себя использование объектов ПотокВПамяти и ЗаписьZIP на сервере, а затем ЧтениеZIP на мобильном приложении. Объект ПотокВПамяти позволяет работать с данными непосредственно в оперативной памяти, что соответствует требованию "без создания файлов на диске".

Рассмотрим по шагам:

  1. Подготовка и сжатие данных в ZIP на сервере 1С:

    На стороне сервера мы будем использовать ПотокВПамяти для создания 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Значение() доступны как на сервере, так и на клиенте (включая мобильное приложение), что делает их идеальными для обмена бинарными данными.

  2. Распаковка ZIP-архива в мобильном приложении 1С:

    Исторически работа с 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.Закрыть();
    ПотокПамятиДляЧтения.Закрыть();
    

Преимущества этого метода:

Недостатки:

Метод 3: Прозрачное сжатие веб-сервером (gzip)

Помимо явного сжатия данных на уровне 1С, существует возможность использования прозрачного сжатия на уровне веб-сервера (например, IIS, Apache, Nginx) с использованием алгоритма gzip. Этот метод работает на транспортном уровне HTTP и является полностью прозрачным для клиента, если он поддерживает gzip (а большинство современных браузеров и мобильных клиентов его поддерживают).

Разберем, как это работает:

  1. Настройка веб-сервера:

    На веб-сервере, который обслуживает HTTP-сервис 1С, включается модуль сжатия. При настроенном сжатии веб-сервер автоматически сжимает HTTP-ответы, если клиент в запросе указывает поддержку сжатия (через заголовок Accept-Encoding: gzip, deflate).

  2. Работа клиента:

    Клиентское приложение (в данном случае мобильное приложение 1С) автоматически отправляет заголовок Accept-Encoding. Если веб-сервер настроен на сжатие и получает такой заголовок, он сжимает ответ и добавляет заголовок Content-Encoding: gzip. Мобильное приложение получает сжатый ответ и автоматически его распаковывает, предоставляя приложению уже распакованные данные.

Преимущества этого метода:

Недостатки:

Учитывая опасения автора относительно отсутствия контроля и гарантий при использовании прозрачного сжатия веб-сервером, мы рекомендуем сосредоточиться на методах, которые предоставляют явный контроль: сериализация в XML/Base64 или явное сжатие в ZIP/Base64.

Рекомендации и выбор метода

При выборе метода передачи данных мы рекомендуем учитывать следующие моменты:

  1. Размер данных: Для небольших объемов данных (килобайты) сериализация в XML с Base64 может быть приемлемой из-за ее простоты. "Хвосты" 1С-ной сериализации не будут играть значительной роли.
  2. Требования к сжатию: Если объем данных большой (сотни килобайт или мегабайты), и требуется максимальное сжатие и контроль над форматом, то метод явного сжатия в ZIP-архив с использованием ПотокВПамяти и Base64Строка будет предпочтительным. Благодаря поддержке ZIP в мобильной платформе 8.3.21+, это стало наиболее универсальным и контролируемым решением.
  3. Универсальность: Использование ДвоичныеДанные в сочетании с Base64Строка() и Base64Значение() является очень гибким подходом, так как ДвоичныеДанные доступны на всех видах клиентов (тонкий клиент, веб-клиент, мобильный клиент и мобильное приложение) и на сервере. Это позволяет свободно передавать бинарные данные между любыми точками системы.
  4. Производительность: Для очень больших объемов данных следует помнить, что сериализация/десериализация и кодирование/декодирование Base64 требуют процессорных ресурсов и памяти. По возможности, такие операции следует выполнять на стороне сервера, передавая на клиент только уже подготовленные и оптимально сжатые данные.

Итоговый вывод: Для преобразования ХранилищаЗначений в двоичные данные и их эффективной передачи в мобильное приложение 1С через HTTP-сервис, когда требуется полный контроль и гарантии, наиболее надежным и рекомендуемым решением является явное сжатие данных в ZIP-архив с использованием объекта ПотокВПамяти на сервере, кодирование получившихся ДвоичныеДанныеZIP в Base64-строку для передачи в JSON, и последующая распаковка и декодирование в мобильном приложении 1С с использованием объектов ЧтениеZIP и Base64Значение(). Этот подход обеспечивает высокую степень сжатия, отсутствие лишних метаданных и полную функциональность на мобильной платформе 1С:Предприятие версии 8.3.21 и выше.

← На главную