Как загрузить файл на FTP из Web-клиента 1С:Предприятие 8.3 без ошибок модальности

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

Разработка под Web-клиент в среде 1С:Предприятие всегда накладывает на программиста ряд ограничений, связанных с безопасностью веб-браузеров. Одной из классических задач, вызывающих трудности у разработчиков, является интерактивный выбор файла на компьютере пользователя и последующая его отправка на внешний FTP-сервер. В то время как на Тонком клиенте этот код пишется буквально в несколько строк и работает напрямую с файловой системой, в Web-клиенте мы сталкиваемся с блокировкой модальных окон и невозможностью прямого доступа к локальным дискам.

В этой статье мы подробно разберем, почему возникают эти сложности, проанализируем архитектуру безопасной работы с файлами в веб-среде и реализуем готовое решение, которое будет работать на платформе 1С:Предприятие 8.3 начиная с версии 8.3.15 без необходимости установки расширения работы с файлами.

Выясняем причины: почему не работает простой код?

Попытка вызвать привычный метод выбора файлов в Web-клиенте часто приводит к ошибке «Использование модальных окон в данном режиме запрещено». Выясним причину этого поведения. Современные веб-браузеры в целях безопасности полностью блокируют синхронные модальные вызовы, которые останавливают выполнение кода страницы до тех пор, пока пользователь не закроет диалоговое окно. Если в свойствах вашей конфигурации 1С для свойства Режим использования модальности установлено значение Не использовать, то вызовы традиционных синхронных методов объекта ДиалогВыбораФайла приведут к аварийному завершению работы.

Вторая проблема заключается в архитектуре FTP-соединения. Объект платформы FTPСоединение физически инициализируется и выполняет отправку данных только на стороне сервера (так как веб-клиент в браузере не имеет возможности устанавливать прямые TCP-соединения с произвольными портами из-за ограничений политики безопасности CORS). Следовательно, файл должен быть сначала передан с клиентского компьютера на сервер 1С.

Многие разработчики совершают ошибку, пытаясь передать адрес временного хранилища (вид навигационной ссылки e1cib/tempstorage/...) напрямую в методы объекта FTPСоединение. Это вызывает ошибку «Файл не найден», поскольку служба FTP-клиента на сервере ожидает получить реальный физический путь к файлу в операционной системе (например, C:\Windows\Temp\tempfile.bin или /tmp/tempfile.bin для Linux), а не внутреннюю ссылку СУБД 1С.

Правильный жизненный цикл передачи файла

Для реализации корректной и стабильной загрузки файла на FTP-сервер мы должны выстроить цепочку событий следующим образом:

  1. На клиенте: инициируем немодальный (асинхронный) выбор файла пользователем с помощью специального диалога.
  2. Передача в хранилище: платформа автоматически и безопасно загружает выбранный файл во временное хранилище на сервере 1С, возвращая клиенту уникальный адрес (навигационную ссылку).
  3. Вызов сервера: передаем полученный адрес временного хранилища и имя исходного файла в серверную процедуру.
  4. На сервере: извлекаем бинарные данные из временного хранилища с помощью метода ПолучитьИзВременногоХранилища().
  5. Создание временного файла: записываем эти двоичные данные в реальный временный файл на диске сервера при помощи функции ПолучитьИмяВременногоФайла(). Это необходимо, так как FTPСоединение работает только с физическими путями.
  6. Отправка на FTP: устанавливаем FTP-соединение и записываем временный файл на удаленный сервер.
  7. Очистка ресурсов: в обязательном порядке удаляем временный файл с диска сервера 1С, чтобы не забивать дисковое пространство временными данными.

Рассмотрим подробнее программную реализацию этой схемы.

Шаг 1. Клиентская часть — немодальный выбор файла

Начиная с версии платформы 1С 8.3.15, разработчикам доступен удобный асинхронный метод НачатьПомещениеФайлаНаСервер(), который не требует предварительной установки расширения работы с файлами в браузере. Настроим параметры диалога с помощью объекта ПараметрыДиалогаПомещенияФайлов и запустим процесс выбора.

Создадим процедуру на клиенте, которая будет привязана к кнопке выбора файла на форме:


&НаКлиенте
Процедура ВыбратьИОтправитьНаFTP(Команда)
    
    // Настраиваем параметры диалога выбора файлов в немодальном режиме
    ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов;
    ПараметрыДиалога.Заголовок = "Выберите файл для отправки на FTP-сервер";
    ПараметрыДиалога.МножественныйВыбор = Ложь;
    ПараметрыДиалога.Фильтр = "Все файлы (*.*)|*.*";
    
    // Описываем процедуру обратного вызова, которая сработает после выбора файла пользователем
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВыбораИПомещенияФайла", ЭтотОбъект);
    
    // Запускаем асинхронный импорт. Файл будет автоматически загружен во временное хранилище
    НачатьПомещениеФайлаНаСервер(ОписаниеОповещения, , , , ПараметрыДиалога, УникальныйИдентификатор);
    
КонецПроцедуры

Теперь проанализируем процедуру обратного вызова ПослеВыбораИПомещенияФайла. Она принимает два параметра, из которых мы получаем всю необходимую информацию о загруженном файле.


&НаКлиенте
Процедура ПослеВыбораИПомещенияФайла(ОписаниеПомещенногоФайла, ДополнительныеПараметры) Экспорт
    
    // Если пользователь закрыл диалоговое окно браузера или отменил выбор
    Если ОписаниеПомещенногоФайла = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Получаем адрес временного хранилища на сервере и оригинальное имя файла
    АдресХранилища = ОписаниеПомещенногоФайла.Адрес;
    ИмяФайла = ОписаниеПомещенногоФайла.СсылкаНаФайл.Имя;
    
    // Передаем управление на сервер для выполнения отправки на FTP
    Попытка
        ОтправитьФайлНаFTPНаСервере(АдресХранилища, ИмяФайла);
        ПоказатьПредупреждение(, "Файл успешно передан на FTP-сервер!");
    Исключение
        ПоказатьПредупреждение(, "Произошла ошибка при отправке файла: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
    КонецПопытки;
    
КонецПроцедуры

Шаг 2. Серверная часть — работа с хранилищем, диском и FTP

Перейдем к серверной логике. Нам необходимо выполнить процедуру с директивой компиляции &НаСервереБезКонтекста. Это позволит оптимизировать производительность и исключит передачу лишнего контекста формы между клиентом и сервером. В этой процедуре мы извлечем объект ДвоичныеДанные, временно запишем его на жесткий диск сервера 1С, установим соединение с удаленным сервером через объект FTPСоединение и отправим данные.

Обратите внимание на блок обработки исключений: мы обязаны гарантировать удаление временного файла с диска сервера 1С при любом исходе операции (успех или ошибка сети), чтобы избежать утечки дисковой памяти.


&НаСервереБезКонтекста
Процедура ОтправитьФайлНаFTPНаСервере(Знач АдресХранилища, Знач ИмяФайла)
    
    // 1. Получаем двоичные данные файла из временного хранилища по переданному адресу
    ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(АдресХранилища);
    
    // 2. Определяем расширение оригинального файла для корректного создания временного файла
    РасширениеФайла = "";
    ПозицияТочки = Найти(ИмяФайла, ".");
    Если ПозицияТочки > 0 Тогда
        РасширениеФайла = Сред(ИмяФайла, ПозицияТочки);
    КонецЕсли;
    
    // 3. Создаем временный файл на физическом диске сервера 1С
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла(РасширениеФайла);
    ДвоичныеДанныеФайла.Записать(ИмяВременногоФайла);
    
    // 4. Подключаемся к FTP-серверу и производим запись
    Попытка
        // Настоятельно рекомендуется использовать пассивный режим работы (Параметр "Истина")
        // для стабильного обхода сетевых экранов и брандмауэров сервера
        FTPСоединение = Новый FTPСоединение("ftp.yoursite.com", 21, "your_login", "your_password", , Истина, 60);
        
        // Передаем физический путь временного файла на сервере и желаемое имя файла на FTP-сервере
        FTPСоединение.Записать(ИмяВременногоФайла, ИмяФайла);
        
    Исключение
        // В случае сбоя сети или авторизации обязательно подчищаем созданный временный файл на сервере
        Попытка
            УдалитьФайлы(ИмяВременногоФайла);
        Исключение
            // Подавляем ошибку удаления временного файла, чтобы выдать основную ошибку подключения
        КонецПопытки;
        
        ВызватьИсключение "Не удалось отправить файл по FTP. Описание ошибки: " + ОписаниеОшибки();
    КонецПопытки;
    
    // 5. Очищаем ресурсы после успешной отправки файла
    Попытка
        УдалитьФайлы(ИмяВременногоФайла);
    Исключение
        // Возможные ошибки удаления пишем в Журнал Регистрации или игнорируем
    КонецПопытки;
    
КонецПроцедуры

Важные рекомендации по работе с FTP в веб-среде

При настройке и отладке данного механизма рекомендуем обратить внимание на следующие технические нюансы:

Таким образом, мы успешно обошли ограничения безопасности Web-клиента, избавились от ошибок несовместимости модального режима работы интерфейса и реализовали надежную и отказоустойчивую схему передачи файлов на внешние ресурсы через сервер 1С.

← На главную