При переходе от файлового режима работы 1С к клиент-серверному, особенно при использовании веб-клиента, многие разработчики сталкиваются с тем, что ранее отлично работающие внешние обработки внезапно перестают функционировать корректно, в частности, не создают выходные файлы. Рассмотрим эту проблему подробно и предложим пошаговое решение.
Изначально, в файловом режиме, внешняя обработка могла напрямую взаимодействовать с локальной файловой системой компьютера пользователя, создавая, читая или записывая файлы. Однако, когда мы публикуем информационную базу через веб-сервер и запускаем ее в веб-клиенте (браузере), картина кардинально меняется. Веб-клиент не имеет прямого доступа к файловой системе пользовательского компьютера из соображений безопасности. Все операции с файлами должны выполняться через сервер 1С:Предприятия.
Основная причина, по которой внешние обработки перестают создавать файлы в веб-клиенте, кроется в архитектурных особенностях. Веб-клиент — это, по сути, страница в браузере, которая общается с сервером 1С. Браузеры по умолчанию запрещают веб-страницам прямой доступ к локальным дискам пользователя, чтобы предотвратить вредоносные действия. Таким образом, любая попытка кода, исполняющегося в контексте веб-клиента, создать или записать файл напрямую на диск пользователя потерпит неудачу.
Нам важно понять, что код, формирующий файл, должен быть выполнен на сервере 1С:Предприятия. После того как файл будет создан на сервере (например, во временном хранилище), он должен быть явно передан на клиент. Только после этого браузер пользователя предложит ему сохранить файл.
Для корректной работы в управляемом приложении (к которому относится ЗУП 3.0 и веб-клиент) критически важно правильно разделять код на клиентский и серверный. Это достигается с помощью директив компиляции:
&НаКлиенте: Код, который выполняется на клиентской стороне (в браузере для веб-клиента или на компьютере пользователя для тонкого клиента). Он не имеет доступа к серверным объектам и файловой системе сервера.&НаСервере: Код, который выполняется на сервере 1С:Предприятия. Он имеет доступ к файловой системе сервера, информационной базе, а также к серверным объектам.&НаКлиентеНаСервере: Код, который может выполняться как на клиенте, так и на сервере. Часто используется для общих функций, которые не зависят от контекста выполнения.Если ваша обработка формирует файл, весь код, который отвечает за создание и запись данных в файл, должен быть помещен в процедуры или функции, выполняющиеся на сервере (с директивой &НаСервере).
Для обмена файлами между сервером и клиентом в 1С используется специальный механизм — временное хранилище. Это позволяет серверу создать файл, поместить его во временное хранилище, а затем передать клиенту ссылку на этот файл. Клиент, получив ссылку, может инициировать скачивание файла.
Сначала мы должны убедиться, что код, генерирующий содержимое файла, выполняется на сервере. Создадим процедуру на сервере, которая формирует файл и сохраняет его во временное хранилище.
Предположим, у нас есть кнопка на форме обработки, по нажатию на которую должен быть создан файл.
&НаКлиенте
Процедура КомандаСформироватьФайл(Команда)
// Вызываем серверную функцию для формирования файла и получения адреса временного хранилища
АдресФайлаНаСервере = СформироватьФайлНаСервере();
// Если файл успешно сформирован и адрес получен
Если НЕ ПустаяСтрока(АдресФайлаНаСервере) Тогда
// Инициируем получение файла с сервера на клиент
НачатьПолучениеФайлаССервера(
АдресФайлаНаСервере,
Новый ОписаниеПередачиФайла(ИмяФайлаДляСохраненияНаКлиенте),
Новый ОписаниеОповещения("ПослеПолученияФайлаССервера", ЭтотОбъект)
);
Иначе
Сообщить("Не удалось сформировать файл на сервере.");
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция СформироватьФайлНаСервере()
// Здесь происходит формирование содержимого файла
// Например, создадим текстовый файл с простым содержимым
ИмяВременногоФайлаНаСервере = ПолучитьИмяВременногоФайла(".txt"); // Получаем уникальное имя файла
ТекстовыйДокумент = Новый ТекстовыйДокумент();
ТекстовыйДокумент.УстановитьТекст("Это содержимое файла, созданного на сервере 1С.");
ТекстовыйДокумент.Записать(ИмяВременногоФайлаНаСервере, КодировкаТекста.UTF8);
// Помещаем файл во временное хранилище и получаем его адрес
АдресВременногоХранилища = ПоместитьФайлВоВременноеХранилище(ИмяВременногоФайлаНаСервере, УникальныйИдентификатор);
// Удаляем временный файл с диска сервера, так как он уже в хранилище
УдалитьФайлы(ИмяВременногоФайлаНаСервере);
Возврат АдресВременногоХранилища;
КонецФункции
&НаКлиенте
Процедура ПослеПолученияФайлаССервера(Результат, ДополнительныеПараметры) Экспорт
Если Результат = Истина Тогда
Сообщить("Файл успешно сохранен на клиентском компьютере.");
Иначе
Сообщить("Сохранение файла на клиентском компьютере отменено или произошла ошибка.");
КонецЕсли;
КонецПроцедуры
Пояснения к коду:
КомандаСформироватьФайл выполняется на клиенте. Она вызывает серверную функцию для формирования файла.СформироватьФайлНаСервере выполняется на сервере. Здесь мы:
ПолучитьИмяВременногоФайла().ТекстовыйДокумент (или любой другой, например, ДвоичныеДанные, ТабличныйДокумент), заполняем его данными и записываем в файл на диске сервера.ПоместитьФайлВоВременноеХранилище() мы перемещаем созданный на сервере файл во внутреннее временное хранилище 1С и получаем его уникальный адрес. Этот адрес и будет передан на клиент.НачатьПолучениеФайлаССервера(). Эта функция асинхронно инициирует загрузку файла с сервера на клиент.НачатьПолучениеФайлаССервера():
ОписаниеПередачиФайла, который содержит рекомендуемое имя файла для сохранения на клиенте. Пользователь увидит это имя в диалоге сохранения.ОписаниеОповещения, который указывает на процедуру (ПослеПолученияФайлаССервера) и объект, который эту процедуру содержит. Эта процедура будет вызвана после завершения операции сохранения файла на клиенте, сообщая нам о ее результате.ПослеПолученияФайлаССервера также выполняется на клиенте и обрабатывает результат сохранения файла.Если мы формируем не текстовый документ, а, например, табличный документ или файл произвольных двоичных данных, подход будет аналогичным:
&НаСервере
Функция СформироватьДвоичныйФайлНаСервере()
// Пример: создание табличного документа
ТабДок = Новый ТабличныйДокумент;
ТабДок.Область("R1C1").Текст = "Пример Таблицы";
// ... дальнейшее заполнение ТабДок ...
// Получаем имя временного файла на сервере
ИмяВременногоФайлаНаСервере = ПолучитьИмяВременногоФайла(".xlsx");
// Сохраняем ТабличныйДокумент в файл на сервере
ТабДок.Записать(ИмяВременногоФайлаНаСервере, ТипФайлаТабличногоДокумента.XLSX);
// Помещаем файл во временное хранилище
АдресВременногоХранилища = ПоместитьФайлВоВременноеХранилище(ИмяВременногоФайлаНаСервере, УникальныйИдентификатор);
// Удаляем временный файл с диска сервера
УдалитьФайлы(ИмяВременногоФайлаНаСервере);
Возврат АдресВременногоХранилища;
КонецФункции
Дальнейший вызов НачатьПолучениеФайлаССервера будет таким же, как и для текстового файла.
В некоторых сценариях, особенно если вам требуется более широкий функционал взаимодействия с локальной файловой системой (например, выбор нескольких файлов из произвольных каталогов или прямой доступ к файлам по пути), может потребоваться установка специального "Расширения работы с файлами" для 1С. Однако это расширение требует интерактивной установки пользователем и может быть ограничено политиками безопасности. Для большинства задач по сохранению файла, сформированного на сервере, оно не требуется, так как НачатьПолучениеФайлаССервера() работает через стандартный диалог сохранения файлов браузера.
Стоит отметить, что в более новых версиях платформы (начиная с 8.3.13.1513) многие операции, связанные с выбором файлов на клиенте (например, НачатьПомещениеФайлов() для загрузки с клиента на сервер), могут работать без этого расширения, используя нативные диалоги браузера.
Иногда проблемы с внешними обработками могут быть связаны не только с кодом, но и с окружением. Убедитесь, что пользователь, от имени которого работает веб-сервер (например, IIS или Apache), имеет достаточные права доступа:
bin).Если веб-сервер настроен неправильно или есть проблемы с правами, даже идеально написанный код не сможет создать или записать файл на сервере.
При возникновении проблем всегда рекомендуем проверять логи:
Для того чтобы ваша внешняя обработка успешно создавала и передавала файлы пользователю через веб-сервер, выполните следующие шаги:
&НаСервере.ПоместитьФайлВоВременноеХранилище(), чтобы получить адрес, по которому клиент сможет забрать файл. Не забудьте удалить временный файл с сервера после помещения в хранилище.НачатьПолучениеФайлаССервера(), передав ей адрес и описание файла.ОписаниеОповещения) для получения информации об успешности или ошибке сохранения файла на клиенте.Следуя этим рекомендациям, вы сможете адаптировать ваши внешние обработки для корректной работы в условиях веб-клиента и обеспечить стабильное формирование и передачу файлов пользователям ЗУП 3.0.