Почему не работает НачатьПомещениеФайла в веб-клиенте 1С и как это исправить

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

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

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

Выясняем причину: почему «теряется» обработчик завершения

Основное различие между тонким и веб-клиентом в данном сценарии кроется в механизме управления памятью (сборщике мусора — Garbage Collector) и особенностях работы асинхронного кода в браузере.

Давайте проанализируем, как выполняется асинхронный вызов команды во внешней обработке (например, при заполнении объекта документа без открытия формы):

  1. Пользователь нажимает кнопку команды заполнения. БСП или платформа создает временный клиентский экземпляр модуля команды или внешней обработки.
  2. В коде инициализируется диалог выбора файла и вызывается асинхронный метод НачатьПомещениеФайла, в который передается ОписаниеОповещения. Это описание содержит ссылку на текущий контекст выполнения (параметр ЭтотОбъект).
  3. В тонком клиенте этот временный объект удерживается платформой в памяти до тех пор, пока интерактивный диалог ожидает выбора файла пользователем.
  4. В веб-клиенте исполнение кода происходит в среде JavaScript браузера. Как только метод, инициирующий диалог выбора файла, завершает свою работу, управление сразу же возвращается браузеру для ожидания действий пользователя. Поскольку сама форма обработки не открыта на экране, на временный вспомогательный объект команды больше не остается жестких (strong) ссылок.
  5. Браузерный сборщик мусора (Garbage Collector) анализирует оперативную память, считает этот объект неиспользуемым «мусором» и физически удаляет его из памяти.
  6. Когда пользователь выбирает файл в системном диалоге и нажимает кнопку «Открыть», браузер пытается вызвать процедуру обратного вызова (callback) на объекте, который уже уничтожен. В результате вызов обработчика завершения «молча» игнорируется, и код не выполняется.

Если же форма обработки открыта интерактивно, она регистрируется в интерфейсе веб-клиента. Платформа принудительно удерживает контекст формы и её модуля в памяти до тех пор, пока пользователь её не закроет. Именно поэтому при открытой форме обработчик оповещения всегда успешно отрабатывает — его контекст физически существует в памяти на момент выбора файла.

Рассмотрим пример исходного проблемного кода, в котором веб-клиент теряет связь с обработчиком оповещения:


#Если ВебКлиент Тогда
    ДиалогВыбораФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    ДиалогВыбораФайла.Заголовок = "Выбор файла для загрузки";
    
    // В веб-клиенте этот вызов завершит процедуру, контекст ЭтотОбъект очистится,
    // и процедура ОкончаниеВыбораФайла никогда не вызовется.
    НачатьПомещениеФайла(
        Новый ОписаниеОповещения("ОкончаниеВыбораФайла", ЭтотОбъект), 
        , 
        ДиалогВыбораФайла, 
        , 
        УникальныйИдентификатор
    );
#КонецЕсли

---

Решение 1. Использование формы-заглушки (метод «якорения» контекста)

Самый быстрый, хотя и не самый элегантный способ обойти ограничение сборщика мусора в веб-клиенте — это принудительное открытие формы внешней обработки. Открытая форма выступает в роли «якоря» для контекста выполнения.

Для реализации этого сценария настройте логику работы команды следующим образом:

  1. В модуле команды внешней обработки определите тип клиента.
  2. Если это веб-клиент, вместо непосредственного вызова процедуры загрузки откройте форму внешней обработки.
  3. На форме обработки разместите кнопку начала импорта или запускайте процесс интерактивного выбора файла сразу при открытии формы (например, в обработчике ПриОткрытии или через обработчик ожидания).
  4. После того как файл будет успешно помещен во временное хранилище и обработан, программно закройте форму обработки с помощью метода Закрыть().

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


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

---

Решение 2. Переход на современные асинхронные методы (Рекомендуется для Платформы 8.3.15+)

Метод НачатьПомещениеФайла признан устаревшим, начиная с версии платформы 8.3.15. В современных версиях 1С:Предприятия для работы с файлами были введены более надежные и оптимизированные асинхронные методы: НачатьПомещениеФайлаНаСервер() и НачатьПомещениеФайловНаСервер().

Эти новые методы спроектированы с учетом полной асинхронности веб-клиента. Они используют специальные объекты параметров и умеют корректно сохранять состояние сессии без жесткой привязки к контексту временных модулей команд. Кроме того, они позволяют загружать файлы в браузерах без предварительной установки расширения работы с файлами.

Давайте разберем пример использования нового метода НачатьПомещениеФайлаНаСервер:


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

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

---

Решение 3. Использование механизмов Библиотеки стандартных подсистем (БСП)

Если ваша конфигурация разработана на базе БСП, настоятельно рекомендуется отказаться от прямых вызовов низкоуровневых методов платформы в пользу стандартных общих модулей подсистемы «Работа с файлами».

Использование методов БСП полностью скрывает от разработчика особенности работы веб-клиента и тонкого клиента, самостоятельно управляя контекстом асинхронного вызова и сессией браузера. Вам больше не придется писать ветвление кода #Если ВебКлиент Тогда.

Рассмотрим, как выглядит загрузка файла через БСП:


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

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

---

Решение 4. Перенос ОписанияОповещения на форму-владелец

Если вы разрабатываете команду заполнения объекта для конкретного документа или справочника, у вас под рукой всегда есть контекст формы самого заполняемого объекта (параметр ВладелецФормы или форма, из которой была запущена внешняя обработка).

Вместо того чтобы передавать временный ЭтотОбъект (модуль внешней обработки) в ОписаниеОповещения, вы можете передать туда контекст формы открытого документа. Сама форма документа гарантированно открыта на экране и удерживается платформой в памяти браузера, поэтому ее методы не будут очищены сборщиком мусора во время выбора файла пользователем.

Для этого:

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

---

Важное замечание о фильтрах файлов в веб-клиенте

При тестировании работы с файлами в веб-клиенте под управлением различных браузеров (Google Chrome, Mozilla Firefox, Яндекс.Браузер) разработчики иногда сталкиваются со специфической ошибкой платформы: при использовании сложных фильтров файлов (например, ограничение строго по расширению .xlsx или .dbf) в интерактивном диалоге выбора файлов кнопка подтверждения («Открыть»/«ОК») может стать неактивной или заблокированной после выбора файла.

Если вы столкнулись с тем, что диалоговое окно открывается, но файл невозможно отправить на сервер, выполните следующие действия:

Применяя данные рекомендации и переходя на современные методы платформы, вы обеспечите стабильную и быструю работу механизмов загрузки файлов в любых веб-клиентах и браузерах!

← На главную