Как организовать выбор файла на клиенте и передать его на сервер для обработки в 1С?

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

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

Почему нельзя просто передать путь к файлу с клиента на сервер?

Проанализируем типичную ошибку начинающих разработчиков: открыть диалог выбора файла на клиенте с помощью объекта ДиалогВыбораФайла, получить локальный путь к файлу (например, C:\Users\User\Documents\export.csv) и передать эту строку параметром в серверную процедуру.

В клиент-серверном режиме работы (на сервере 1С:Предприятия) этот подход работать не будет по следующим причинам:

  1. Изоляция файловых систем: служба сервера 1С выполняется на отдельном физическом или виртуальном сервере и не имеет прямого доступа к дискам клиентского рабочего места.
  2. Права доступа: служба кластера 1С работает под собственной системной учетной записью (например, USR1CV8), у которой нет прав на чтение пользовательских каталогов на локальных машинах.
  3. Режим работы без модальности и веб-клиент: синхронный вызов метода ДиалогВыбораФайла.Выбрать() вызывает ошибку блокировки интерфейса в современных версиях платформы и полностью не поддерживается в веб-клиенте.

Единственно верный способ передачи файла с клиентского компьютера на сервер — это чтение двоичных данных на клиенте, помещение их во временное хранилище и передача на сервер уникального адреса этого хранилища.

Способ 1. Использование современного асинхронного метода ПоместитьФайлНаСерверАсинх

Начиная с версии платформы 8.3.18, наиболее удобным и лаконичным способом является вызов асинхронной функции ПоместитьФайлНаСерверАсинх. Она объединяет в себе вызов стандартного диалога выбора файла и автоматическую отправку выбранных данных во временное хранилище.

Рассмотрим реализацию на клиенте:


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

Обратим внимание на передачу параметра УникальныйИдентификатор формы в метод помещения файла. Это критически важно: если передать Неопределено, временное хранилище будет очищено сразу после первого серверного вызова, и при дальнейшей работе файл может оказаться недоступен.

Способ 2. Использование механизма оповещений (НачатьПомещениеФайлаНаСервер)

Если в конфигурации не используются асинхронные функции через оператор Ждать, применим классический паттерн с объектом ОписаниеОповещения.

Посмотрим на пример клиентского кода:


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

&НаКлиенте
Процедура ВыборФайлаЗавершение(РезультатПомещения, ДополнительныеПараметры) Экспорт
    
    Если РезультатПомещения = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    ВыгрузитьТоварыНаСервере(РезультатПомещения.Адрес, РезультатПомещения.СсылкаНаФайл.Имя);
    
КонецПроцедуры

Обработка полученного файла на стороне сервера

Теперь разберем серверную процедуру. Получив адрес во временном хранилище, сервер извлекает объект ДвоичныеДанные с помощью функции ПолучитьИзВременногоХранилища. Если внешний обработчик или API требует обязательного наличия файла на диске сервера, мы сохраняем его во временный каталог сервера, отправляем и обязательно удаляем после завершения операции.


&НаСервере
Процедура ВыгрузитьТоварыНаСервере(АдресВХ, ИсходноеИмяФайла)
    
    // Получаем двоичные данные из временного хранилища
    ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВХ);
    
    Если ДвоичныеДанные = Неопределено Тогда
        ВызватьИсключение "Не удалось прочитать файл из временного хранилища.";
    КонецЕсли;
    
    // Генерируем уникальное имя временного файла на сервере
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("csv");
    КаталогВременныхФайловСервера = КаталогВременныхФайлов();
    
    Попытка
        // Сохраняем файл на диск сервера
        ДвоичныеДанные.Записать(ИмяВременногоФайла);
        
        // Проверяем факт создания файла на сервере
        ФайлНаДиске = Новый Файл(ИмяВременногоФайла);
        Если ФайлНаДиске.Существует() Тогда
            
            ПараметрыОтправки = Новый Структура;
            ПараметрыОтправки.Вставить("Режим", 0);
            ПараметрыОтправки.Вставить("СерверПриемник", УбратьПротоколВАдресе(АдресСайтаPost));
            ПараметрыОтправки.Вставить("APIKey", APIKey);
            ПараметрыОтправки.Вставить("ИмяФайла", ИмяВременногоФайла);
            ПараметрыОтправки.Вставить("ВремКаталог", КаталогВременныхФайловСервера);
            ПараметрыОтправки.Вставить("ВерсияПлатформыAdvantShop", 1);
            
            ОтправитьФайл(ПараметрыОтправки);
            
        КонецЕсли;
        
    Исключение
        // Обязательно удаляем временный файл даже при возникновении ошибок
        УдалитьФайлы(ИмяВременногоФайла);
        УдалитьИзВременногоХранилища(АдресВХ);
        ВызватьИсключение;
    КонецПопытки;
    
    // Очищаем временные ресурсы после успешной отправки
    УдалитьФайлы(ИмяВременногоФайла);
    УдалитьИзВременногоХранилища(АдресВХ);
    
КонецПроцедуры

Важные нюансы и частые ошибки при работе с файлами

  1. Проверка существования файла: метод НайтиФайлы() всегда возвращает массив (даже если файлов не найдено). Конструкция Если НайтиФайлы(...) <> Неопределено является ошибкой. Для проверки существования используйте объект Файл и его метод Существует() либо проверяйте НайтиФайлы(...).Количество() > 0.
  2. Очистка временных файлов: при выгрузке файлов на диск сервера обязательно используйте блоки Попытка ... Исключение с вызовом УдалитьФайлы(), чтобы избежать переполнения дискового пространства сервера сессионными файлами.
  3. Управление памятью: после завершения обработки обязательно освобождайте оперативную память вызовом процедуры УдалитьИзВременногоХранилища(АдресВХ).
← На главную