Как передать массив двоичных данных в веб-сервис 1С?

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

При интеграции систем часто возникает задача передачи файлов через веб-сервисы. Если с передачей одного файла все относительно просто (для этого используется стандартный тип base64Binary), то передача целого массива двоичных данных в рамках одного запроса в SOAP-сервисах 1С может вызвать затруднения. Особенно это актуально для устаревших версий платформы (например, 1С 8.3.4), где еще нет полноценной поддержки легковесных HTTP-сервисов, и разработчикам приходится работать исключительно в рамках протокола SOAP.

В этой статье мы подробно разберем несколько эффективных способов решения этой задачи, начиная от простых обходных путей с применением JSON и заканчивая профессиональными архитектурными паттернами для обмена большими объемами данных.

Вариант 1. Сериализация массива в формат JSON

Давайте рассмотрим один из самых популярных и простых в реализации подходов, который не требует глубокой настройки внутренней структуры веб-сервиса и создания кастомных XDTO-пакетов. Суть метода заключается в том, что все файлы на стороне клиента кодируются в формат Base64, упаковываются в массив, преобразуются в JSON-строку и передаются в веб-сервис в качестве одного строкового параметра.

Разберем этот процесс по шагам со стороны клиента и сервера:

  1. На стороне клиента (например, PHP): Мы считываем файлы, кодируем их содержимое с помощью функции base64_encode(), формируем стандартный массив строк и сериализуем его в JSON-строку с помощью функции json_encode().
  2. На стороне веб-сервиса 1С: Наш метод принимает один параметр с типом string (из пространства имен http://www.w3.org/2001/XMLSchema).

Давайте проанализируем пример кода на стороне 1С, который выполняет десериализацию полученной JSON-строки и восстанавливает файлы:


// Функция веб-сервиса, принимающая JSON-строку с массивом файлов
Функция ПринятьМассивФайловВФорматеJSON(ДанныеФайловJSON) Экспорт
    
    // Инициализируем чтение JSON
    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(ДанныеФайловJSON);
    
    Попытка
        МассивСтрокBase64 = ПрочитатьJSON(ЧтениеJSON);
        ЧтениеJSON.Закрыть();
    Исключение
        ЧтениеJSON.Закрыть();
        ВызватьИсключение "Не удалось разобрать входящий JSON-пакет: " + ОписаниеОшибки();
    КонецПопытки;
    
    Если ТипЗнч(МассивСтрокBase64) <> Тип("Массив") Тогда
        ВызватьИсключение "Переданные данные не являются массивом!";
    КонецЕсли;
    
    // Обходим массив и восстанавливаем двоичные данные
    Для Каждого СтрокаBase64 Из МассивСтрокBase64 Цикл
        
        Попытка
            // Преобразуем Base64 обратно в ДвоичныеДанные
            ДвоичныеДанныеФайла = ПолучитьДвоичныеДанныеИзСтрокиBase64(СтрокаBase64);
            
            // Здесь выполняем сохранение двоичных данных в базу (например, в ХранилищеЗначения)
            // или записываем на диск во временный файл
            ИмяВременногоФайла = ПолучитьИмяВременногоФайла();
            ДвоичныеДанныеФайла.Записать(ИмяВременногоФайла);
            
        Исключение
            // Логируем ошибку обработки конкретного файла
            ЗаписьЖурналаРегистрации("ВебСервис.ЗагрузкаФайлов", 
                УровеньЖурналаРегистрации.Ошибка, , , 
                "Ошибка обработки файла: " + ОписаниеОшибки());
        КонецПопытки;
        
    КонецЦикла;
    
    Возврат "Успешно обработано файлов: " + МассивСтрокBase64.Количество();
    
КонецФункции

Преимущества метода: Простота реализации, отсутствие необходимости настраивать сложные типы в конфигурации 1С, легкая интеграция с любыми внешними языками программирования (PHP, Python, JS), которые имеют встроенную поддержку JSON.

Вариант 2. Создание собственного XDTO-пакета для списка файлов

Если мы хотим оставаться в рамках строгой типизации SOAP и XML-стандартов, то правильным решением будет создание собственного XDTO-пакета. Это позволит веб-сервису автоматически валидировать структуру входящего XML-запроса.

Выясним, как правильно настроить свойства объектов XDTO в конфигураторе 1С:

  1. Создайте новый Пакет XDTO в дереве метаданных. Задайте ему уникальное пространство имен, например: http://www.myservice.ru/files.
  2. Добавьте в этот пакет Тип объекта с именем FileTransferElement. Добавьте в него свойство FileData с типом base64Binary (из пространства http://www.w3.org/2001/XMLSchema) и свойство FileName с типом string.
  3. Добавьте еще один Тип объекта с именем ArrayOfFiles. Добавьте в него свойство File.
  4. Важный шаг настройки: В свойствах поля File укажите тип FileTransferElement, а свойствам МинимальноеКоличество и МаксимальноеКоличество задайте значения 0 и -1 (Unbounded) соответственно. Это укажет платформе 1С, что данное свойство является списком (массивом).
  5. В свойствах операции вашего веб-сервиса укажите для входного параметра созданный тип ArrayOfFiles из вашего пространства имен XDTO.

Рассмотрим, как обрабатывать такие строго типизированные данные в коде веб-сервиса 1С:


Функция ЗагрузитьФайлыЧерезXDTO(СписокФайловXDTO) Экспорт
    
    // На стороне 1С параметр СписокФайловXDTO представит собой ОбъектXDTO
    // Доступ к списку элементов осуществляется через свойство "File"
    СписокЭлементов = СписокФайловXDTO.File;
    
    Для Каждого ЭлементXDTO Из СписокЭлементов Цикл
        
        // Получаем имя файла и двоичные данные
        ИмяФайла = ЭлементXDTO.FileName;
        
        // Платформа автоматически преобразует base64Binary во временный файл или ДвоичныеДанные
        ДвоичныеДанные = ЭлементXDTO.FileData; 
        
        // Пример сохранения в базу данных
        НовыйДокумент = Справочники.ХранилищеФайлов.СоздатьЭлемент();
        НовыйДокумент.Наименование = ИмяФайла;
        НовыйДокумент.ДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанные);
        НовыйДокумент.Записать();
        
    КонецЦикла;
    
    Возврат "Файлы успешно импортированы";
    
КонецФункции

Вариант 3. Использование универсального типа anyType

Если вам не хочется создавать кастомные XDTO-пакеты в конфигурации, но при этом хочется передавать массив данных стандартными средствами SOAP-сериализации XML, можно использовать встроенный универсальный тип anyType.

Посмотрим на особенности этого метода:

Проанализируем пример обработки параметра с типом anyType:


Функция ОбработатьУниверсальныйМассив(ДанныеМассива) Экспорт
    
    Если ТипЗнч(ДанныеМассива) = Тип("СписокXDTO") Тогда
        
        Для Каждого ЭлементСписка Из ДанныеМассива Цикл
            // Извлекаем значение из XDTO-объекта
            СтрокаBase64 = ЭлементСписка.Значение;
            
            Попытка
                ДвоичныеДанные = ПолучитьДвоичныеДанныеИзСтрокиBase64(СтрокаBase64);
                // Обработка двоичных данных...
            Исключение
                Продолжить;
            КонецПопытки;
        КонецЦикла;
        
    КонецЕсли;
    
    Возврат "Обработка завершена";
    
КонецФункции

Вариант 4. Стандартный пакет core от 1С

Платформа 1С содержит встроенный системный пакет XDTO, описывающий базовые типы данных платформы. Мы можем использовать его для передачи стандартного массива:

  1. В свойствах веб-сервиса найдите поле Пакеты XDTO и добавьте туда стандартный системный пакет http://v8.1c.ru/8.1/data/core.
  2. Для параметра вашей операции веб-сервиса укажите тип Array из этого пакета.
  3. Для чтения переданного массива в коде 1С используйте встроенный глобальный сериализатор:

// Преобразуем XDTO-структуру "Array" напрямую в привычный Массив 1С
МассивФайлов = СериализаторXDTO.ПрочитатьXDTO(ПараметрМассиваXDTO);

Для Каждого СтрокаBase64 Из МассивФайлов Цикл
    ДвоичныеДанные = ПолучитьДвоичныеДанныеИзСтрокиBase64(СтрокаBase64);
    // Выполняем запись
КонецЦикла;

Архитектурные ограничения и профессиональное решение (Chunking)

Передача больших массивов файлов за один SOAP-запрос содержит в себе скрытые инфраструктурные риски, о которых важно помнить разработчику:

Для создания надежных и отказоустойчивых систем обмена используется паттерн поблочной передачи (Chunking). Давайте разберем по шагам, как построить такую архитектуру:

  1. На стороне клиента все передаваемые файлы упаковываются в один ZIP-архив.
  2. Клиент замеряет объем архива. Если он превышает лимит (например, 2 МБ), клиент делит его на части (блоки) фиксированного размера.
  3. В веб-сервисе 1С создается метод для поблочной загрузки со следующей сигнатурой: PutFilePart(FileID, PartNumber, PartData, TotalParts).
  4. Клиент последовательно отправляет части файла, вызывая данный метод.

Рассмотрим пример реализации сборки поблочно передаваемого файла на стороне 1С:


Функция PutFilePart(FileID, PartNumber, PartData, TotalParts) Экспорт
    
    // Определяем путь к временному файлу на сервере 1С
    ИмяВременногоФайла = КаталогВременныхФайлов() + FileID + ".tmp";
    
    // Преобразуем текущую часть из Base64 в ДвоичныеДанные
    ДвоичныеДанныеЧасти = ПолучитьДвоичныеДанныеИзСтрокиBase64(PartData);
    
    // Записываем полученную часть в конец собираемого файла
    // Параметр "Истина" указывает на дозапись (добавление в конец файла)
    ЗаписьДанных = Новый ЗаписьДанных(ИмяВременногоФайла, , , Истина);
    ЗаписьДанных.Записать(ДвоичныеДанныеЧасти);
    ЗаписьДанных.Закрыть();
    
    // Если получена последняя часть, выполняем обработку файла
    Если Число(PartNumber) = Число(TotalParts) Тогда
        
        Попытка
            // Временный файл полностью собран. Так как это ZIP-архив, распаковываем его
            Архив = Новый ЧтениеZipФайла(ИмяВременногоФайла);
            ПутьРаспаковки = КаталогВременныхФайлов() + FileID;
            Архив.ИзвлечьВсе(ПутьРаспаковки, РежимВосстановленияПутейФайловZip.НеВосстанавливать);
            Архив.Закрыть();
            
            // Читаем извлеченные файлы и записываем их в БД
            НайденныеФайлы = НайтиФайлы(ПутьРаспаковки, "*.*");
            Для Каждого Файл Из НайденныеФайлы Цикл
                ДвоичныеДанныеФайла = Новый ДвоичныеДанные(Файл.ПолноеИмя);
                
                // Сохранение в базу данных 1С...
                
                // Удаляем временный распакованный файл
                УдалитьФайлы(Файл.ПолноеИмя);
            КонецЦикла;
            
            // Удаляем сам архив и папку распаковки
            УдалитьФайлы(ИмяВременногоФайла);
            УдалитьФайлы(ПутьРаспаковки);
            
        Исключение
            УдалитьФайлы(ИмяВременногоФайла);
            ВызватьИсключение "Ошибка сборки и обработки архива: " + ОписаниеОшибки();
        КонецПопытки;
        
        Возврат "Файл успешно собран и обработан";
        
    КонецЕсли;
    
    Возврат "Часть " + PartNumber + " из " + TotalParts + " успешно получена";
    
КонецФункции

Использование поблочной передачи гарантирует стабильную работу интеграции при любом качестве интернет-соединения и позволяет передавать гигабайты информации без перерасхода оперативной памяти сервера приложений 1С.

← На главную