В процессе разработки в системе 1С:Предприятие часто возникает задача программного извлечения файлов, которые хранятся внутри базы данных — для этого есть обработка выгрузки файлов из базы 1С. Это могут быть макеты с двоичными данными (например, шаблоны Word или Excel), прикрепленные файлы в справочниках или изображения, полученные с мобильного устройства. Основная сложность заключается в том, что код, успешно работающий в толстом или тонком клиенте, часто выдает ошибку доступа в веб-клиенте из-за политик безопасности браузера.
В данной статье мы разберем, как правильно организовать процесс сохранения файлов, проанализируем типичные ошибки доступа и рассмотрим современные асинхронные методы платформы 8.3.
Чаще всего разработчики сталкиваются с ошибкой при использовании метода ДвоичныеДанные.Записать(). Давайте выясним причину. В веб-клиенте 1С работает внутри «песочницы» браузера. Это означает, что веб-приложение не имеет прямого доступа к файловой системе вашего компьютера по соображениям безопасности. Попытка записать файл по прямому пути, например, D:\123.docx, всегда будет приводить к отказу в доступе.
Более того, согласно синтаксис-помощнику, метод Записать() объекта ДвоичныеДанные недоступен в веб-клиенте. Он работает только на стороне сервера, толстого клиента или мобильного приложения. Для решения этой задачи нам потребуется передать данные с сервера на клиент и инициировать процедуру скачивания через браузер.
Прежде чем сохранить файл, его нужно получить на сервере. Рассмотрим стандартный подход, если данные хранятся в макете или табличной части документа — здесь пригодится обработка формирования Word-документов по шаблонам. Проанализируем пример функции, которая находит данные в базе и возвращает их:
&НаСервере
Функция ПолучитьДвоичныеДанныеНаСервере(НомерСтроки)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПрикрепленныеДанные.Данные,
| ПрикрепленныеДанные.Расширение
|ИЗ
| Документ.Заявка.ПрикрепленныеДанные КАК ПрикрепленныеДанные
|ГДЕ
| ПрикрепленныеДанные.Ссылка = &Ссылка И ПрикрепленныеДанные.НомерСтроки = &НомерСтроки";
Запрос.УстановитьПараметр("НомерСтроки", НомерСтроки);
Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Если Выборка.Следующий() Тогда
// Извлекаем двоичные данные из ХранилищаЗначения
Возврат Выборка.Данные.Получить();
КонецЕсли;
Возврат Неопределено;
КонецФункции
Важный момент: если данные хранятся в ХранилищеЗначения, обязательно используйте метод Получить(), чтобы извлечь объект ДвоичныеДанные (поможет инструмент вывода факсимиле в печатные формы).
Чтобы сохранить файл в веб-клиенте, мы должны использовать механизм временного хранилища. Рассмотрим по шагам, как это реализовать:
ПолучитьФайл(), передавая этот адрес.Посмотрим на пример клиентского кода:
&НаКлиенте
Процедура ОткрытьИСохранитьФайл(Команда)
ТекущаяСтрока = Элементы.ПрикрепленныеДанные.ТекущиеДанные;
#Если ВебКлиент Тогда
// Подключаем расширение для работы с файлами
Если Не ПодключитьРасширениеРаботыСФайлами() Тогда
УстановитьРасширениеРаботыСФайлами();
ПодключитьРасширениеРаботыСФайлами();
КонецЕсли;
#КонецЕсли
// Получаем данные с сервера
ДвоичныеДанные = ПолучитьДвоичныеДанныеНаСервере(ТекущаяСтрока.НомерСтроки);
Если ДвоичныеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
// Помещаем во временное хранилище
АдресВХ = ПоместитьВоВременноеХранилище(ДвоичныеДанные, ЭтаФорма.УникальныйИдентификатор);
// Формируем имя файла
ИмяФайла = "Документ_" + Строка(Новый УникальныйИдентификатор) + "." + ТекущаяСтрока.Расширение;
// Инициируем получение файла пользователем
// Третий параметр "Истина" открывает диалог выбора пути
ПолучитьФайл(АдресВХ, ИмяФайла, Истина);
КонецПроцедуры
Использование Новый УникальныйИдентификатор гарантирует, что имена файлов не будут конфликтовать, если пользователь решит сохранить несколько документов подряд.
Начиная с версии 1С 8.3.15, использование синхронных методов вроде ПолучитьФайл() считается устаревшим (deprecated) и в некоторых режимах работы браузеров может блокироваться. Рекомендуется переходить на асинхронную модель работы. Вместо ПолучитьФайл() используем НачатьПолучениеФайлаССервера().
Рассмотрим, как изменится наш подход:
&НаКлиенте
Процедура СохранитьФайлАсинхронно(Команда)
// ... логика получения АдресаВХ аналогична ...
ПараметрыФайла = Новый ОписаниеПередаваемогоФайла(ИмяФайла, АдресВХ);
НачатьПолучениеФайлаССервера(Новый ОписаниеОповещения("ЗавершитьПолучениеФайла", ЭтотОбъект), АдресВХ, ИмяФайла);
КонецПроцедуры
&НаКлиенте
Процедура ЗавершитьПолучениеФайла(Результат, ДополнительныеПараметры) Экспорт
Если Результат <> Неопределено Тогда
Сообщить("Файл успешно передан браузеру для сохранения.");
КонецЕсли;
КонецПроцедуры
Этот метод более «дружелюбен» к современным браузерам (Chrome, Safari, Firefox), так как он не блокирует интерфейс пользователя во время передачи данных.
Если ваша задача связана с мобильным приложением (как упоминалось в сообщениях форума), работа с файлами имеет свои нюансы. Мобильная платформа 1С позволяет использовать СредстваМультимедиа для создания фото. Данные снимка можно сразу преобразовать в ДвоичныеДанные и сохранить в базу.
Чтобы открыть такой файл на мобильном устройстве, мы должны сначала сохранить его во временный каталог устройства с помощью ДвоичныеДанные.Записать() (который доступен в мобильном приложении), а затем вызвать ЗапуститьПриложение(). Система сама предложит подходящую программу для просмотра (Word, галерея и т.д.).
Даже при правильном коде веб-клиент может выдавать предупреждения безопасности. Чтобы минимизировать их:
В ходе обсуждения также поднимался вопрос ошибки в общем модуле при использовании факсимиле (удобно через расширение для подстановки факсимиле в формы). Если вы столкнулись с ошибкой Метод объекта не обнаружен (ДвоичныеДанныеФаксимилеФизическогоЛица) в расширении, скорее всего, произошло обновление типовой конфигурации (например, БП 3.0), где разработчики 1С изменили состав общего модуля УправлениеПечатьюБП. В таких случаях рекомендуется выполнить глобальный поиск по конфигурации, чтобы найти новое имя функции или перенести логику формирования факсимиле в свое расширение, используя прямые запросы к регистру сведений ЛичныеКарточки или аналогичным объектам хранения подписей.
Резюмируем: Для сохранения файла из двоичных данных в веб-клиенте 1С основной связкой методов является ПоместитьВоВременноеХранилище() на сервере и ПолучитьФайл() (или его асинхронный аналог) на клиенте. Прямая запись на диск через Записать() в браузере невозможна.