При разработке конфигураций на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда функционал, идеально работающий в толстом или тонком клиенте, отказывается функционировать в веб-клиенте. Одной из таких задач является отображение PDF-файлов непосредственно в форме документа с помощью поля HTML-документа. Рассмотрим, почему стандартный подход через навигационные ссылки e1cib часто выдает ошибку "Не удалось загрузить PDF-документ", и разберем несколько надежных способов решения этой проблемы.
В толстом клиенте 1С использует внутренние механизмы рендеринга (часто базирующиеся на движке Internet Explorer), которые понимают протокол e1cib. Однако, когда мы открываем базу через браузер (Chrome, Firefox, Safari), мы попадаем в песочницу безопасности браузера. Современные браузеры блокируют попытки тегов <embed> или <iframe> загрузить данные по внутренним ссылкам 1С, так как они не являются стандартными URL. Кроме того, браузер не всегда может корректно передать авторизационные куки сессии 1С внутрь объекта <embed>, что приводит к ошибке доступа.
Разберем по шагам альтернативные методы, которые позволят нам добиться стабильного отображения документов во всех популярных браузерах.
Проанализируем самый быстрый в реализации метод. Его суть заключается в том, чтобы не заставлять браузер переходить по ссылке за файлом, а передать все содержимое PDF-файла непосредственно в HTML-коде в закодированном виде.
Рассмотрим пример реализации на сервере:
&НаСервере
Процедура ЗагрузитьPDFВПолеHTML()
// Получаем двоичные данные из присоединенного файла или хранилища значений
ДвоичныеДанные = Объект.ДанныеРезюме.Получить();
Если ДвоичныеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
// Преобразуем двоичные данные в строку Base64
СтрокаBase64 = Base64Строка(ДвоичныеДанные);
// Формируем HTML-текст с использованием Data URI
// Используем iframe, так как он лучше поддерживается мобильными браузерами
ТекстHTML = "<html><body style='margin:0; padding:0;'>";
ТекстHTML = ТекстHTML + "<iframe src='data:application/pdf;base64," + СтрокаBase64 + "' width='100%' height='100%' style='border:none;'></iframe>";
ТекстHTML = ТекстHTML + "</body></html>";
// Реквизит формы, связанный с полем HTML-документа
Объект.ПолеHTML = ТекстHTML;
КонецПроцедуры
Важный нюанс: метод Base64 отлично подходит для небольших документов (до 5–10 Мб). Если PDF-файл очень объемный, строка Base64 станет огромной, что может привести к зависанию формы при передаче данных с сервера на клиент или к ограничениям браузера по длине URL.
Выясним, как сделать отображение PDF максимально "профессиональным". Этот метод заключается в создании собственного HTTP-сервиса внутри вашей конфигурации, который будет отдавать файл по стандартному HTTP-адресу. Это снимает все проблемы с безопасностью браузеров.
Рассмотрим алгоритм действий:
GetPDF)./view/{FileID}.GET напишем код, который извлекает файл по его идентификатору и возвращает его в теле ответа.Пример кода метода GET в HTTP-сервисе:
Функция viewGet(Запрос)
ИдентификаторФайла = Запрос.ПараметрыШаблона.Получить("FileID");
// Логика получения данных файла из базы
ДвоичныеДанные = ПолучитьФайлИзХранилища(ИдентификаторФайла);
Результат = Новый HTTPСервисОтвет(200);
Результат.Заголовки.Вставить("Content-Type", "application/pdf");
// Установка Content-Disposition: inline заставляет браузер открыть файл внутри, а не скачивать
Результат.Заголовки.Вставить("Content-Disposition", "inline; filename=""document.pdf""");
Результат.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанные);
Возврат Результат;
КонецФункции
Теперь в поле HTML достаточно передать обычную ссылку на ваш сервис: <iframe src="/ВашаБаза/hs/GetPDF/view/ID_файла"></iframe>. Браузер воспримет это как обычный PDF-ресурс и задействует встроенный просмотрщик.
Если нам нужно обеспечить одинаковое отображение PDF во всех браузерах (даже если в браузере пользователя отключены плагины для PDF), проанализируем вариант с использованием библиотеки PDF.js от Mozilla. Это "золотой стандарт" для веб-разработки.
Для этого выполним следующие действия:
Преимущество этого метода в том, что вы получаете полный контроль над интерфейсом просмотра: кнопками печати, масштабирования и поиска, которые будут выглядеть одинаково в Chrome, Safari и Firefox.
Посмотрим на наиболее производительный способ для современных браузеров, который минимизирует объем передаваемого HTML-текста. Мы можем передать двоичные данные на клиент и создать так называемую Blob-ссылку с помощью JavaScript.
Пример реализации в модуле формы:
&НаКлиенте
Процедура ПоказатьPDF(РезультатЗагрузки)
// Предположим, мы получили адрес во временном хранилище
АдресФайла = РезультатЗагрузки.Адрес;
// В поле HTML у нас загружена заготовка со скриптом
ТекстJS = "
| var xhr = new XMLHttpRequest();
| xhr.open('GET', '" + АдресФайла + "', true);
| xhr.responseType = 'blob';
| xhr.onload = function(e) {
| if (this.status == 200) {
| var blob = new Blob([this.response], {type: 'application/pdf'});
| var url = URL.createObjectURL(blob);
| document.getElementById('pdf-frame').src = url;
| }
| };
| xhr.send();";
Элементы.ПолеHTML.ВыполнитьСкрипт(ТекстJS);
КонецПроцедуры
Подведем итоги нашего исследования. Выбор метода зависит от архитектуры вашей системы:
<embed>) используйте PDF.js или <iframe>.Важный совет: не забывайте про расширение работы с файлами. Хотя автор темы упоминал ПодключитьРасширениеРаботыСФайлами(), помните, что оно отвечает за взаимодействие с файловой системой пользователя (выгрузка/загрузка), но никак не влияет на отображение PDF внутри браузера. За рендеринг отвечает исключительно движок браузера или подключенные JS-библиотеки.