Как декодировать и сохранить файл Base64, полученный через Web-сервис и XDTO в 1С?

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

При интеграции 1С со сторонними Web-сервисами (SOAP) часто возникает задача передачи двоичных файлов: прайс-листов, документов, изображений или отчетов. Нередко файл упаковывается в архив и передается в виде текстовой строки в формате Base64 внутри объекта ОбъектXDTO. Однако попытка преобразовать полученную строку через стандартную функцию Base64Значение() может вернуть пустой результат или вызвать ошибку. Разберем по шагам, почему это происходит и как правильно получить, декодировать и сохранить файл.

Причина 1. Невалидная строка Base64 и служебные символы

Проанализируем структуру полученной строки. Встроенная функция платформы Base64Значение() очень чувствительна к формату входных данных. Внешние сервисы при сериализации Base64 могут добавлять переносы строк для ограничения длины, пробелы или использовать нестандартное кодирование.

Рассмотрим основные варианты некорректных данных и способы их нормализации:

  1. Переносы строк и пробелы. Если строка содержит символы \r\n, \n или пробелы, их необходимо удалить перед передачей в функцию декодирования.
  2. URL-Safe кодирование (RFC 4648). Некоторые API заменяют символы + на - и / на _, а также убирают символы дополнения = в конце строки. Платформа 1С не сможет декодировать такую строку без обратной замены.
  3. Префиксы Data URI. Если строка начинается с заголовка вида data:application/zip;base64,, этот префикс необходимо отсечь до запятой.

Посмотрим на пример универсальной очистки строки перед декодированием:


// Очищаем строку от пробелов и переносов строк
СтрокаBase64 = СтрЗаменить(СтрЗаменить(СтрЗаменить(ИсходнаяСтрока, Символы.ПС, ""), Символы.ВК, ""), " ", "");

// Проверяем наличие Data URI и отсекаем его
ПозицияЗапятой = СтрНайти(СтрокаBase64, ",");
Если ПозицияЗапятой > 0 И СтрНайти(Лев(СтрокаBase64, ПозицияЗапятой), "base64") > 0 Тогда
    СтрокаBase64 = Сред(СтрокаBase64, ПозицияЗапятой + 1);
КонецЕсли;

// Преобразуем URL-safe Base64 в стандартный Base64
СтрокаBase64 = СтрЗаменить(СтрЗаменить(СтрокаBase64, "-", "+"), "_", "/");

// Дополняем выравнивание до кратности 4
Остаток = СтрДлина(СтрокаBase64) % 4;
Если Остаток > 0 Тогда
    СтрокаBase64 = СтрокаBase64 + СтрШаблон("%1", ?(Остаток = 2, "==", "="));
КонецЕсли;

// Получаем двоичные данные
ДвоичныеДанныеФайла = Base64Значение(СтрокаBase64);

Причина 2. Описание типа свойства в пакете XDTO

Выясним причину на уровне архитектуры SOAP-сервиса. По умолчанию, если свойство в WSDL или XSD схеме пакета XDTO описано как xs:string, платформа 1С читает его как обычную текстовую строку. В этом случае программисту приходится вручную вызывать Base64Значение().

Если же в схеме пакета XDTO для свойства указать тип base64Binary (пространство имен http://www.w3.org/2001/XMLSchema), платформа выполнит автоматическое преобразование при десериализации ответа. Свойство полученного объекта ОбъектXDTO сразу будет содержать тип ДвоичныеДанные, и необходимость в ручном декодировании полностью отпадет.

Посмотрим на пример обращения к свойству при правильной типизации XDTO:


// Если свойство типизировано как xs:base64Binary
ДвоичныеДанныеФайла = Ответ.pricelist_encoded_file;

// Проверяем тип полученного значения
Если ТипЗнч(ДвоичныеДанныеФайла) = Тип("ДвоичныеДанные") Тогда
    ПутьКФайлу = ПолучитьИмяВременногоФайла("zip");
    ДвоичныеДанныеФайла.Записать(ПутьКФайлу);
КонецЕсли;

Распаковка и обработка полученного архива

Разберем ситуацию, когда во флаге ответа сервиса указано, что файл передается в сжатом виде (например, price_list_zipped = 1). После получения двоичных данных их необходимо сохранить во временный файл и распаковать с помощью объекта ЧтениеZipФайла.

Рассмотрим полный алгоритм распаковки и чтения файлов из архива:

  1. Сохраняем полученные ДвоичныеДанные во временный ZIP-файл с помощью метода ПолучитьИмяВременногоФайла("zip").
  2. Создаем каталог для распаковки содержимого.
  3. Инициализируем объект ЧтениеZipФайла и извлекаем все файлы.
  4. Обрабатываем извлеченные данные (например, читаем файл прайс-листа формата XML, CSV или XLSX).
  5. Удаляем временные файлы и папки после завершения работы.

Посмотрим на пример кода распаковки архива:


ВременныйZip = ПолучитьИмяВременногоФайла("zip");
КаталогРаспаковки = КаталогВременныхФайлов() + "Прайс_" + Строка(Новый УникальныйИдентификатор) + "\";

// Сохраняем двоичные данные на диск
ДвоичныеДанныеФайла.Записать(ВременныйZip);

// Распаковываем архив
Архив = Новый ЧтениеZipФайла(ВременныйZip);
Архив.ИзвлечьВсе(КаталогРаспаковки, РежимВосстановленияПутейФайловZIP.НеВосстанавливать);
Архив.Закрыть();

// Обрабатываем извлеченные файлы
НайденныеФайлы = НайтиФайлы(КаталогРаспаковки, "*.*");
Для Каждого Файл Из НайденныеФайлы Цикл
    // Выполняем чтение и обработку файла прайс-листа
    Сообщить("Извлечен файл: " + Файл.Имя);
КонецЦикла;

// Очищаем временные файлы
УдалитьФайлы(ВременныйZip);
УдалитьФайлы(КаталогРаспаковки);

Таким образом, при работе с Base64 через Web-сервисы всегда проверяйте корректность описания типов в пакетах XDTO и очищайте входную строку от лишних символов перед декодированием.

← На главную