Интеграция 1С с внешними веб-ресурсами и корпоративными порталами часто требует отображения готовых отчетов прямо в браузере или мобильном приложении. Разберем, как устроен механизм передачи данных табличного документа через HTTP-сервис платформы 1С:Предприятие, какие форматы передачи данных подходят лучше всего и как реализовать программное формирование отчета без лишней нагрузки на дисковую подсистему сервера.
Проанализируем классический вариант, при котором табличный документ генерируется на стороне сервера, сохраняется во временный файл в формате HTML5, считывается и передается в браузер в теле HTTP-ответа.
Рассмотрим реализацию метода сохранения табличного документа в текстовую строку:
ИмяВремФайла = ПолучитьИмяВременногоФайла("html");
ТаблДокСОтчетом.Записать(ИмяВремФайла, ТипФайлаТабличногоДокумента.HTML5);
ТекстДок = Новый ТекстовыйДокумент;
ТекстДок.Прочитать(ИмяВремФайла, КодировкаТекста.UTF8);
ТекстОтчетаHTML = ТекстДок.ПолучитьТекст();
УдалитьФайлы(ИмяВремФайла);
Полученный текст разметки передается в обработчик сервиса. Рассмотрим структуру типового метода GET для HTTP-сервиса:
Функция ОтчетыGet(Запрос)
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-Type", "text/html; charset=utf-8");
// Формируем отчет в переменную ТаблДок
ТаблДок = СформироватьНужныйОтчет();
ИмяВремФайла = ПолучитьИмяВременногоФайла("html");
ТаблДок.Записать(ИмяВремФайла, ТипФайлаТабличногоДокумента.HTML5);
ТекстДок = Новый ТекстовыйДокумент;
ТекстДок.Прочитать(ИмяВремФайла, КодировкаТекста.UTF8);
ТекстОтчетаHTML = ТекстДок.ПолучитьТекст();
Попытка
УдалитьФайлы(ИмяВремФайла);
Исключение
КонецПопытки;
Ответ.УстановитьТелоИзСтроки(ТекстОтчетаHTML, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Возврат Ответ;
КонецФункции
Постоянная запись временных файлов на жесткий диск и их последующее чтение создают дополнительную нагрузку на серверную операционную систему и замедляют обработку запросов. Избавимся от дисковых операций ввода-вывода (I/O) с помощью объекта ПотокВПамяти. Метод Записать() объекта ТабличныйДокумент умеет выгружать данные напрямую в поток.
Разберем по шагам быстрый способ генерации ответа без использования файлов:
Функция ОтчетыПотокGet(Запрос)
ТаблДок = СформироватьНужныйОтчет();
Поток = Новый ПотокВПамяти;
ТаблДок.Записать(Поток, ТипФайлаТабличногоДокумента.HTML5);
ДвоичныеДанныеОтчета = Поток.ЗакрытьИПолучитьДвоичныеДанные();
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-Type", "text/html; charset=utf-8");
Ответ.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеОтчета);
Возврат Ответ;
КонецФункции
Если сгенерированный HTML-документ необходимо внедрить внутрь страницы сайта, а не открывать в отдельной вкладке, могут возникнуть конфликты встроенных CSS-стилей платформы со стилями сайта. Выделим основные пути решения этой задачи:
div со своим классом и изолируем правила CSS.iframe. В этом случае браузер изолирует стили и скрипты отчета от основного портала.style из выгруженного отчета и переносим его в блок head главной страницы.При выгрузке отчетов с диаграммами или логотипами экспорт в HTML имеет существенный недостаток: платформа создает отдельные графические файлы и ссылается на них относительными путями, из-за чего браузер не сможет их отобразить без дополнительной передачи картинок. Кроме того, форматирование HTML-таблиц может искажаться в зависимости от движка браузера.
Проанализируем альтернативный и надежный способ — отдачу отчета в формате PDF:
Функция ОтчетPDFGet(Запрос)
ТаблДок = СформироватьНужныйОтчет();
Поток = Новый ПотокВПамяти;
ТаблДок.Записать(Поток, ТипФайлаТабличногоДокумента.PDF);
ДвоичныеДанныеPDF = Поток.ЗакрытьИПолучитьДвоичныеДанные();
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-Type", "application/pdf");
Ответ.Заголовки.Вставить("Content-Disposition", "inline; filename=""report.pdf""");
Ответ.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеPDF);
Возврат Ответ;
КонецФункции
Заголовок Content-Disposition со значением inline указывает браузеру, что документ нужно открыть во встроенном средстве просмотра PDF, а не скачивать на диск.
Обработчик HTTP-сервиса всегда исполняется в серверном контексте без клиентских окон и возможности открыть форму отчета интерактивно. Если отчет спроектирован на базе Системы компоновки данных, его инициализация выполняется программно:
ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных") нужного объекта конфигурации.КомпоновщикНастроек, программно заполняем необходимые параметры и значения отборов.КомпоновщикМакета.ПроцессорКомпоновкиДанных и последовательно выводим результат в ТабличныйДокумент с использованием объекта ПроцессорВыводаТабличногоДокументаВТабличныйДокумент.Веб-серверы (Apache, IIS, Nginx) принудительно обрывают входящее соединение при превышении времени ожидания (обычно от 30 до 60 секунд), возвращая клиенту ошибку 504 Gateway Timeout. Если формирование отчета занимает много времени, синхронный вызов приведет к сбою.
Для тяжелых отчетов применяем асинхронную схему:
ФоновыеЗадания.Выполнить(). Внутри задания отчет формируется и помещается во временное хранилище. Сервис сразу возвращает клиенту код 202 Accepted и строковый идентификатор фонового задания.ФоновыеЗадания.НайтиПоУникальномуИдентификатору().ПолучитьИзВременногоХранилища() и отдает клиенту итоговый файл.Также помним о настройке файла публикации default.vrd: для высоконагруженных сценариев важно настраивать пул сеансов, чтобы платформа не тратила ресурсы на повторный запуск сеанса при каждом входящем HTTP-запросе.