Почему не отображаются картинки при возврате HTML из HTTP-сервиса 1С и как это исправить?

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

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

Причина проблемы: как 1С формирует HTML-документ

Проанализируем механизм работы платформы при выполнении метода сохранения табличного документа:

ТабличныйДокумент.Записать(ИмяФайлаHTML, ТипФайлаТабличногоДокумента.HTML);

При таком вызове платформа 1С создает не только сам файл разметки с расширением .html, но и отдельную директорию на диске сервера с именем ИмяФайла_files. В эту папку сохраняются все графические элементы, содержащиеся в табличном документе (логотипы, штрихкоды, подписи, печати). В результирующем HTML-коде теги <img> содержат относительные ссылки на локальные файлы в этой подпапке.

Когда HTTP-сервис возвращает клиенту только текст HTML-страницы, браузер на стороне пользователя парсит полученный код и пытается выполнить отдельные HTTP-запросы по указанным относительным путям. Так как в конфигурации 1С для этих путей нет настроенных обработчиков, веб-сервер возвращает ошибку 404 Not Found, и изображения не отображаются.

Способ 1. Встраивание изображений в тело HTML (Base64 / Data URL)

Рассмотрим наиболее универсальное решение, которое позволяет отдать страницу единым документом без необходимости настраивать дополнительные маршруты на веб-сервере. Для этого заменим относительные пути к файлам картинок на их представление в формате Data URL с кодированием в Base64.

Разберем по шагам реализацию данного алгоритма:

  1. Сохраняем табличный документ во временный файл на сервере.
  2. Считываем текст HTML-документа.
  3. Находим созданную платформой папку с суффиксом _files.
  4. Обходим все файлы изображений в каталоге, считываем их двоичные данные и кодируем с помощью функции Base64Строка().
  5. Заменяем относительные пути в HTML-тексте на конструкцию вида data:image/png;base64,<СтрокаBase64>.
  6. Удаляем временные файлы и возвращаем полученный HTML в теле ответа HTTP-сервиса.

Посмотрим на пример функции для преобразования разметки:


Функция ПолучитьHTMLСВнедреннымиКартинками(ТабличныйДокумент) Экспорт

    КаталогВременныхФайлов = КаталогВременныхФайлов();
    ИмяФайлаHTML = КаталогВременныхФайлов + "report_" + Строка(Новый УникальныйИдентификатор) + ".html";
    ПапкаФайлов = КаталогВременныхФайлов + "report_" + Строка(Новый УникальныйИдентификатор) + "_files";
    
    ТабличныйДокумент.Записать(ИмяФайлаHTML, ТипФайлаТабличногоДокумента.HTML);
    
    ЧтениеТекста = Новый ЧтениеТекста(ИмяФайлаHTML, КодировкаТекста.UTF8);
    ТекстHTML = ЧтениеТекста.Прочитать();
    ЧтениеТекста.Закрыть();
    
    ФайлыКартинок = НайтиФайлы(ПапкаФайлов, "*.*");
    Для Каждого ФайлКартинки Из ФайлыКартинок Цикл
        ДвоичныеДанные = Новый ДвоичныеДанные(ФайлКартинки.ПолноеИмя);
        Base64Данные = Base64Строка(ДвоичныеДанные);
        
        Расширение = НРег(ФайлКартинки.Расширение);
        Если Расширение = ".jpg" Или Расширение = ".jpeg" Тогда
            ТипMIME = "image/jpeg";
        ИначеЕсли Расширение = ".png" Тогда
            ТипMIME = "image/png";
        ИначеЕсли Расширение = ".gif" Тогда
            ТипMIME = "image/gif";
        Иначе
            ТипMIME = "application/octet-stream";
        КонецЕсли;
        
        DataURL = "data:" + ТипMIME + ";base64," + Base64Данные;
        ОтносительныйПуть = ФайлКартинки.Имя;
        ТекстHTML = СтрЗаменить(ТекстHTML, ОтносительныйПуть, DataURL);
        
        УдалитьФайлы(ФайлКартинки.ПолноеИмя);
    КонецЦикла;
    
    Попытка
        УдалитьФайлы(ПапкаФайлов);
        УдалитьФайлы(ИмяФайлаHTML);
    Исключение
        // Обработка исключения очистки временных файлов
    КонецПопытки;
    
    Возврат ТекстHTML;

КонецФункции

Способ 2. Использование готового функционала БСП

Если разработка ведется в типовой или доработанной конфигурации, содержащей Библиотеку стандартных подсистем (БСП), нам не нужно писать парсер вручную. В подсистеме печати уже реализована готовая экспортная процедура:

УправлениеПечатью.ВставитьКартинкиВHTML(ИмяФайлаHTML);

Данная процедура автоматически находит связанную папку с ресурсами, конвертирует все графические элементы в Data URL и перезаписывает исходный HTML-файл. После этого остается лишь прочитать файл в строку и передать в тело ответа через HTTPСервисОтвет.УстановитьТелоИзСтроки().

Способ 3. Добавление отдельного шаблона URL в HTTP-сервис

Если объем изображений велик, встраивание их через Base64 увеличивает размер документа примерно на 33%. В этом случае оптимально отдавать изображения отдельными HTTP-запросами:

  1. В объекте HTTPСервис создаем дополнительный шаблон URL, например: /images/{ИмяКартинки}.
  2. В обработчике метода GET считываем двоичные данные запрошенного файла и возвращаем их с соответствующим заголовком Content-Type (image/png или image/jpeg).
  3. В результирующем HTML заменяем пути на абсолютные или относительные веб-адреса этого маршрута сервиса.

Способ 4. Альтернативные форматы выгрузки

Если формат HTML не является строго обязательным для клиентского приложения, рассмотрим альтернативные варианты выгрузки:

  1. PDF (ТипФайлаТабличногоДокумента.PDF) — наиболее надежный формат для отображения печатных форм. Все изображения автоматически упаковываются внутрь одного бинарного файла. В ответе HTTP-сервиса возвращаются двоичные данные с заголовком Content-Type: application/pdf. Большинство современных веб-браузеров отображают PDF встроенными средствами.
  2. MHT (ТипФайлаТабличногоДокумента.MHT) — веб-архив, содержащий разметку и картинки в одном файле (тип содержимого multipart/related). Однако следует учитывать, что многие современные браузеры скачивают данный формат как файл вместо прямого отображения страницы.
← На главную