При разработке в среде 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда код, идеально работающий в тонком клиенте, начинает вести себя непредсказуемо в веб-клиенте. Одной из классических проблем является «молчаливое» невыполнение процедур обратного вызова (оповещений) после интерактивного выбора файлов. Пользователь выбирает файл в диалоговом окне браузера, нажимает кнопку открытия, но далее ничего не происходит: процедура обратного вызова, переданная в ОписаниеОповещения, попросту не запускается.
В этой статье мы подробно разберем, почему веб-клиент «теряет» форму внешней обработки, рассмотрим архитектурные особенности асинхронной работы браузеров, а также предоставим пошаговые инструкции и примеры кода для решения этой проблемы с использованием современных методов платформы.
Проанализируем детально причины этой проблемы и пути ее решения.
Основная техническая причина, по которой в веб-клиенте не вызывается процедура завершения, заключается в разнице механизмов управления памятью в тонком клиенте и в веб-браузере.
Когда вы запускаете внешнюю обработку (особенно через механизм дополнительных отчетов и обработок БСП) в тонком клиенте, платформа удерживает в оперативной памяти весь контекст формы и модуля до тех пор, пока не завершится асинхронный процесс. В веб-клиенте ситуация иная:
НачатьПомещениеФайла управление моментально передается браузеру для отображения системного диалога выбора файлов.ЭтаФорма из памяти.ЭтаФорма больше не существует, вызов аннулируется без генерации системных ошибок.Как решить эту проблему: Самым надежным способом сохранения жизненного цикла формы является перенос логики во встроенные объекты конфигурации или создание расширения. Формы, описанные в метаданных конфигурации или расширения, жестко контролируются внутренним роутером веб-клиента, и платформа гарантированно сохраняет их экземпляры в памяти браузера до полного окончания всех асинхронных вызовов.
Внешние обработки в современных конфигурациях по умолчанию запускаются в безопасном режиме. Это накладывает серьезные ограничения на работу с файловой системой. В веб-клиенте эти ограничения удваиваются требованиями безопасности самого браузера (песочницей JavaScript). Браузер блокирует попытки совершения небезопасных асинхронных операций, исходящих от динамически загружаемых скриптов, которыми, по сути, и являются формы внешних обработок. Использование расширений конфигурации позволяет выполнять код в доверенном контексте, снимая данные ограничения.
Если в вашем коде используется метод НачатьПомещениеФайла совместно с объектом ДиалогВыбораФайла, веб-клиент будет настойчиво требовать установки специального расширения работы с файлами для браузера (компоненты extra-файлов). В современных браузерах (Google Chrome, Firefox, Opera последних версий) поддержка старых технологий плагинов (NPAPI) полностью прекращена. Попытка установить расширение работы с файлами часто превращается в бесконечный цикл: платформа просит установить расширение, пользователь соглашается, но браузер блокирует его интеграцию, и оповещение снова не отрабатывает.
Начиная с версии 8.3.15, фирма «1С» кардинально переработала механизмы работы с файловой системой в веб-клиенте. Метод НачатьПомещениеФайла признан устаревшим.
Рассмотрим, как выглядит устаревший код, который приводит к сбоям на веб-клиенте:
// ПРИМЕР КОДА, КОТОРЫЙ ВЫЗЫВАЕТ ОШИБКИ В ВЕБ-КЛИЕНТЕ
&НаКлиенте
Процедура ЗагрузитьФайлСтарымСпособом(Команда)
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Заголовок = "Выберите файл для загрузки";
ОбработкаОкончанияЗагрузки = Новый ОписаниеОповещения("Обработчик_Завершения_Загрузки", ЭтаФорма, Диалог);
// Этот метод устарел и требует установки расширения браузера
НачатьПомещениеФайла(ОбработкаОкончанияЗагрузки, , Диалог, Истина, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура Обработчик_Завершения_Загрузки(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
// В веб-клиенте этот код во внешней обработке часто вообще не выполняется!
Если Результат Тогда
ПоказатьПредупреждение(, "Файл успешно загружен: " + ВыбранноеИмяФайла);
КонецЕсли;
EndПроцедуры
Выясним, как переписать этот алгоритм под современные стандарты платформы, чтобы он гарантированно работал в любом браузере без установки дополнительных компонентов.
Для того чтобы обойти ограничения веб-клиента и избавиться от необходимости устанавливать расширение работы с файлами, мы должны использовать метод НачатьПомещениеФайлаНаСервер. Этот метод использует стандартный HTML5 File API вашего браузера, что делает процедуру выбора файла абсолютно нативной и безопасной.
Разберем по шагам правильную реализацию загрузки файла, которая будет стабильно работать как в тонком, так и в веб-клиенте (включая внешние обработки, если они корректно удерживают фокус).
Вместо объекта ДиалогВыбораФайла мы применим специальный класс ПараметрыДиалогаПомещенияФайлов.
&НаКлиенте
Процедура ЗагрузитьФайлСовременно(Команда)
// Создаем параметры диалога вместо старого ДиалогВыбораФайла
ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов;
ПараметрыДиалога.МножественныйВыбор = Ложь;
ПараметрыДиалога.Заголовок = "Выберите файл для импорта в систему";
ПараметрыДиалога.Фильтр = "Текстовые файлы (*.txt)|*.txt|Все файлы (*.*)|*.*";
// Описываем оповещение, указывая экспортную процедуру текущей формы
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВыбораФайлаНаСервер", ЭтаФорма);
// Запускаем асинхронное помещение файла на сервер.
// Данный метод НЕ требует установки расширения работы с файлами в браузере!
НачатьПомещениеФайлаНаСервер(ОписаниеОповещения, , , ПараметрыДиалога, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ПослеВыбораФайлаНаСервер(РезультатПомещения, ДополнительныеПараметры) Экспорт
// Проверяем, завершил ли пользователь выбор файла успешно
Если РезультатПомещения = Неопределено Тогда
Возврат; // Пользователь закрыл диалог выбора файла
КонецЕсли;
Если РезультатПомещения.ИмяФайла = "" Тогда
ПоказатьПредупреждение(, "Файл не был выбран!");
Возврат;
КонецЕсли;
// Получаем адрес во временном хранилище и имя файла
АдресХранилища = РезультатПомещения.Адрес;
ИмяВыбранногоФайла = РезультатПомещения.СсылкаНаФайл.Имя;
// Передаем управление на сервер для обработки двоичных данных
ОбработатьЗагруженныйФайлНаСервере(АдресХранилища, ИмяВыбранногоФайла);
ПоказатьПредупреждение(, "Файл """ + ИмяВыбранногоФайла + """ успешно загружен и обработан!");
КонецПроцедуры
В приведенном выше примере платформа 1С самостоятельно берет на себя управление трансляцией вызова в веб-интерфейс. Помещение файла происходит напрямую во временное хранилище на сервере 1С, что избавляет нас от необходимости писать громоздкий код передачи двоичных данных вручную.
Если специфика вашего прикладного решения требует использования именно внешних обработок (например, если логика часто меняется и обновлять конфигурацию или расширение нежелательно), но вы продолжаете сталкиваться с проблемой потери контекста ЭтаФорма, выполните следующие шаги:
Рассмотрим пример правильного программного открытия формы из модуля внешней обработки с сохранением контекста:
&НаКлиенте
Процедура ОткрытьФормуОбработкиДляЗагрузки(Команда)
// Вместо работы в контексте "непривязанной" внешней обработки,
// откроем форму явно через менеджер окон платформы
ПараметрыФормы = Новый Структура;
ОткрытьФорму("ВнешняяОбработка.МояЗагрузкаДанных.Форма.ФормаЗагрузки", ПараметрыФормы, ЭтаФорма, Истина);
КонецПроцедуры
При использовании нового класса ПараметрыДиалогаПомещенияФайлов в веб-клиенте разработчики иногда сталкиваются с неприятным багом: в системном окне выбора файлов кнопка «Открыть» («ОК») становится серой (неактивной) после выбора нужного файла. Это происходит из-за некорректной интерпретации маски фильтра расширений в некоторых браузерах.
Если вы столкнулись с таким поведением, рекомендуется временно отключить фильтрацию файлов по маске, оставив свойство Фильтр незаполненным, либо упростить его структуру до стандартного вида:
// Если кнопка выбора блокируется, упростите фильтр:
ПараметрыДиалога.Фильтр = "Все файлы (*.*)|*.*";
Подведем итог. Стабильная работа с файлами в веб-клиенте 1С строится на трех правилах: использование асинхронных методов версии платформы 8.3.15+ (таких как НачатьПомещениеФайлаНаСервер), отказ от использования устаревших модальных окон и диалогов, а также обеспечение гарантированного выживания контекста формы на время ожидания ответа пользователя.