Как исправить ошибку XDTO при передаче тяжелого табличного документа с фотографиями с сервера на клиент?

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

При разработке в среде 1С:Предприятие 8.3 программисты часто сталкиваются с необходимостью вывода отчетов или документов, содержащих большое количество графической информации. Типичная ситуация: на сервере формируется ТабличныйДокумент, в него программно добавляются изображения (например, сканы документов или фотографии товаров), и этот объект возвращается на клиент для отображения пользователю. Однако, когда суммарный объем изображений превышает определенный порог (в нашем случае около 130 МБ), система выдает критическую ошибку преобразования данных XDTO.

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

Почему возникает ошибка при передаче данных?

Разберем ситуацию с технической точки зрения. Когда мы вызываем функцию с директивой &НаСервере и возвращаем из нее объект типа ТабличныйДокумент, платформа выполняет автоматическую сериализацию этого объекта в формат XML для передачи по протоколу HTTP. В этот момент происходят следующие процессы:

  1. Кодирование Base64: Все бинарные данные (картинки), содержащиеся в табличном документе, преобразуются в текстовую строку формата Base64. Это увеличивает объем передаваемых данных примерно на 30–33%. Таким образом, 130 МБ фотографий превращаются в ~175 МБ текста в XML-пакете.
  2. Ограничения парсера XDTO: При получении этого пакета на стороне клиента парсер XDTO пытается десериализовать данные. Ошибка Ошибка отображения типов часто связана с тем, что система не может выделить непрерывный блок памяти для обработки гигантской строки Base64, особенно если используется 32-битный тонкий клиент.
  3. Лимиты памяти: Даже если физической оперативной памяти достаточно, 32-битный процесс ограничен адресным пространством, и фрагментация памяти не позволяет обработать один огромный объект «одним куском».

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


&НаСервере
Функция ПосмотретьСканыНаСервере()
    ТабДок = Новый ТабличныйДокумент;
    // ... логика заполнения документа картинками
    Возврат ТабДок; // Ошибка происходит здесь при передаче на клиент
КонецФункции

&НаКлиенте
Процедура ПосмотретьСканы(Команда)
    ТабДок = ПосмотретьСканыНаСервере();
    Если ТабДок <> Неопределено Тогда
        ТабДок.Показать();
    КонецЕсли;
КонецПроцедуры

Рассмотрим подробнее способы обхода этой проблемы, которые позволяют передавать данные стабильно и быстро.

Решение №1: Использование временного хранилища

Первый и наиболее простой способ оптимизации — исключить прямую передачу тяжелого объекта как возвращаемого значения функции. Вместо этого мы можем поместить сформированный ТабличныйДокумент во временное хранилище на сервере и передать на клиент только адрес (строку-идентификатор).

Выясним, почему это работает лучше. При использовании ПоместитьВоВременноеХранилище() данные передаются в специализированный кэш сервера, а на клиент возвращается лишь короткая ссылка. Последующее получение данных на клиенте через ПолучитьИзВременногоХранилища() во многих версиях платформы оптимизировано и менее чувствительно к лимитам XDTO-сериализатора.

Реализуем этот подход по шагам:


&НаСервере
Функция СформироватьТабДокВоВременноеХранилище()
    ТабДок = Новый ТабличныйДокумент;
    // ... цикл заполнения ТабДок картинками
    // Сохраняем объект и получаем адрес
    АдресХранилища = ПоместитьВоВременноеХранилище(ТабДок, ЭтаФорма.УникальныйИдентификатор);
    Возврат АдресХранилища;
КонецФункции

&НаКлиенте
Процедура ПосмотретьСканы(Команда)
    Адрес = СформироватьТабДокВоВременноеХранилище();
    // На клиенте получаем объект по адресу
    НашТабДок = ПолучитьИзВременногоХранилища(Адрес);
    НашТабДок.Показать("Просмотр изображений");
КонецПроцедуры

Важный нюанс: Обязательно передавайте УникальныйИдентификатор формы во второй параметр функции ПоместитьВоВременноеХранилище(). Это гарантирует, что данные будут жить ровно столько, сколько открыта форма, и будут автоматически удалены после её закрытия, не забивая память сервера.

Решение №2: Передача через MXL-файл и двоичные данные

Если первый способ не помогает (например, из-за крайне жестких ограничений по памяти на клиенте), воспользуемся самым надежным методом — передачей через формат MXL в виде ДвоичныхДанных. Этот метод считается «золотым стандартом» при работе с очень тяжелыми отчетами.

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

Разберем реализацию этого алгоритма:


&НаСервере
Функция ПолучитьТабДокКакДвоичныеДанные()
    ТабДок = Новый ТабличныйДокумент;
    // ... заполнение документа
    
    // Создаем временное имя файла на сервере
    ИмяФайла = ПолучитьИмяВременногоФайла("mxl");
    ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.MXL);
    
    // Читаем файл в объект ДвоичныеДанные
    Данные = Новый ДвоичныеДанные(ИмяФайла);
    
    // Удаляем временный файл с сервера сразу после прочтения
    УдалитьФайлы(ИмяФайла);
    
    Возврат ПоместитьВоВременноеХранилище(Данные);
КонецФункции

&НаКлиенте
Процедура ПосмотретьСканы(Команда)
    Адрес = ПолучитьТабДокКакДвоичныеДанные();
    ДанныеССервера = ПолучитьИзВременногоХранилища(Адрес);
    
    // На клиенте записываем данные во временный файл
    ИмяФайлаКлиент = ПолучитьИмяВременногоФайла("mxl");
    ДанныеССервера.Записать(ИмяФайлаКлиент);
    
    // Читаем в табличный документ
    НовыйТабДок = Новый ТабличныйДокумент;
    НовыйТабДок.Прочитать(ИмяФайлаКлиент);
    НовыйТабДок.Показать();
    
    // Не забываем за собой чистить
    УдалитьФайлы(ИмяФайлаКлиент);
КонецПроцедуры

Дополнительные рекомендации по оптимизации

Помимо способов передачи данных, важно обратить внимание на то, как именно картинки попадают в ТабличныйДокумент. Если мы используем оригинальные фотографии весом по 5–10 МБ каждая, мы быстро исчерпаем ресурсы системы.

Рассмотрим несколько советов по оптимизации графики на сервере:

  1. Предварительное сжатие: Перед добавлением картинки в Рисунок.Картинка, попробуйте изменить её разрешение. В 1С для этого можно использовать объект ОбработкаКартинок (в новых версиях) или внешние библиотеки. Для просмотра на экране монитора часто достаточно разрешения 1024x768.
  2. Формат изображений: Убедитесь, что вы используете компактные форматы (например, JPG с умеренным качеством вместо тяжелых BMP или PNG с прозрачностью).
  3. Очистка метаданных: Иногда файлы содержат огромные блоки метаданных (EXIF, эскизы). Пересохранение картинки на сервере «очищает» её, что уменьшает размер объекта Картинка и предотвращает ошибки десериализации.
  4. Использование 64-битного клиента: Если позволяет инфраструктура, переход на 64-битную версию тонкого клиента полностью снимает проблему лимита памяти в 2 ГБ, что позволяет открывать даже очень тяжелые документы без ухищрений с MXL-файлами.

Подводя итог, можно сказать, что проблема «Ошибка преобразования данных XDTO» при передаче табличного документа — это сигнал о том, что объем данных превысил возможности стандартного механизма передачи. Используя временное хранилище или MXL-контейнеры, вы сможете обойти эти ограничения и обеспечить стабильную работу вашей информационной системы.

← На главную