Разработка и Конфигурация · 12 мин
Как вызвать клиентскую процедуру с сервера в 1С
Разбираем, почему сервер не может напрямую вызвать клиентскую процедуру в 1С, и показываем рабочие способы: оповещения, ожидание, возврат значений и типовые ошибки.
Прямой вызов клиентской процедуры из серверного кода в 1С невозможен: сервер и клиент выполняются в разных процессах, а директивы компиляции &НаСервере и &НаКлиенте жёстко разделяют контексты. Если попытаться обратиться к клиентской процедуре из серверного метода, конфигуратор выдаст ошибку проверки модулей, а в редких случаях обхода — код упадёт в момент выполнения.
Однако задача «после серверной обработки сделать что-то на клиенте» возникает постоянно: показать сообщение, открыть форму, обновить данные, запустить фоновую обработку. Для этого платформа предлагает набор легальных механизмов: возврат значений из серверной функции, оповещения форм, обработчики ожидания, фоновые задания с оповещением о завершении и систему взаимодействия. Ниже разберём каждый вариант с кодом и условиями применения.
Главный принцип прост: не сервер дёргает клиента, а клиент сам инициирует обмен. Клиент вызывает серверную процедуру, получает результат и сам решает, что делать дальше. Либо клиент подписывается на событие и реагирует, когда серверная сторона публикует оповещение. Понимание этой асимметрии избавляет от большинства ошибок проектирования.
Почему сервер не может вызвать клиентскую процедуру
В клиент-серверной архитектуре 1С сервер приложений и клиентское приложение — это разные процессы, часто на разных машинах. Серверный код не имеет доступа к памяти клиента, его формам, интерфейсу и тем более не может «дотянуться» до процедуры, скомпилированной в клиентском контексте. Директива &НаКлиенте означает, что код существует только в клиентском процессе.
Дополнительное ограничение — модальность и безопасность. Серверная транзакция может выполняться долго, а клиент в это время ничего не ждёт в интерактивном смысле: связь идёт по запрос-ответной модели. Сервер отвечает только тогда, когда клиент его спросил. Поэтому любая схема «сервер сам позвонит клиенту» требует обходных механизмов, встроенных в платформу.
Способ 1. Вернуть результат из серверной функции и обработать на клиенте
Самый частый и правильный приём: клиент вызывает серверную функцию, та выполняет работу и возвращает структуру с результатом, а клиент по этим данным решает, что показать или открыть. Фактически «вызов клиентской логики с сервера» здесь заменяется передачей команды через возвращаемое значение.
&НаСервере
Функция ПровестиДокументНаСервере(Ссылка)
Результат = Новый Структура;
Результат.Вставить("Успешно", Истина);
Результат.Вставить("ТекстСообщения", "Документ проведён");
Результат.Вставить("НужноОткрытьОтчет", Ложь);
// ... логика проведения ...
Возврат Результат;
КонецФункции
&НаКлиенте
Процедура Провести(Команда)
Результат = ПровестиДокументНаСервере(Объект.Ссылка);
Если Результат.Успешно Тогда
ПоказатьПредупреждение(, Результат.ТекстСообщения);
Если Результат.НужноОткрытьОтчет Тогда
ОткрытьФорму("Отчет.Продажи.Форма");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Возвращать можно только сериализуемые типы: примитивы, структуры, массивы, таблицы значений, ссылки. Нельзя вернуть элемент формы, COM-объект или несериализуемый объект — получите ошибку преобразования данных. Если данных много, упакуйте их в структуру и отдавайте одним объектом, чтобы не плодить серверные вызовы.
Способ 2. Оповещения форм: Оповестить и ОбработкаОповещения
Если нужно уведомить открытые формы о событии, используйте механизм оповещений. Вызов Оповестить() доступен и на сервере (в контексте формы — через ОповеститьОбИзменении для ссылок), но чаще схема выглядит так: клиент выполняет серверный вызов, а затем сам рассылает оповещение всем заинтересованным формам.
&НаКлиенте
Процедура ЗаписатьИОповестить(Команда)
ЗаписатьНаСервере();
Оповестить("ИзмененСтатусЗаказа", Объект.Ссылка, ЭтотОбъект);
КонецПроцедуры
// В другой форме:
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
Если ИмяСобытия = "ИзмененСтатусЗаказа" Тогда
Элементы.Список.Обновить();
КонецЕсли;
КонецПроцедуры
Для стандартных изменений данных есть ОповеститьОбИзменении(Ссылка) — эта процедура доступна и на сервере, и автоматически обновляет динамические списки и открытые формы объекта. Это ближайший аналог «вызова клиента с сервера»: сервер помечает данные как изменённые, а платформа сама уведомляет клиентские формы.
Способ 3. Фоновые задания с оповещением о завершении
Длительные серверные операции не стоит выполнять синхронно — клиент зависнет. Платформа позволяет запустить фоновое задание и подписаться на его завершение: когда сервер закончит, на клиенте сработает указанная процедура-оповещение. Это полноценный асинхронный «обратный вызов» с сервера.
&НаКлиенте
Процедура ЗапуститьОбработку(Команда)
ПараметрыПроцедуры = Новый Структура("Период", Период);
Оповещение = Новый ОписаниеОповещения("ПослеЗавершенияОбработки", ЭтотОбъект);
НачатьВыполнениеДлительнойОперации(Оповещение, ПараметрыПроцедуры);
КонецПроцедуры
&НаКлиенте
Процедура ПослеЗавершенияОбработки(Результат, ДопПараметры) Экспорт
Если Результат.Статус = "Выполнено" Тогда
Данные = ПолучитьИзВременногоХранилища(Результат.АдресРезультата);
ПоказатьПредупреждение(, "Обработка завершена");
Иначе
ПоказатьПредупреждение(, "Ошибка: " + Результат.КраткоеПредставлениеОшибки);
КонецЕсли;
КонецПроцедуры
Результат работы фонового задания передаётся через временное хранилище: серверная процедура помещает данные по адресу, клиент забирает их после оповещения. Проверяйте статус выполнения — задание могло завершиться с ошибкой, и тогда адрес результата будет пустым.
- 1На клиенте сформируйте параметры и создайте ОписаниеОповещения с именем процедуры-обработчика
- 2Запустите фоновое задание (длительную операцию), передав параметры и оповещение
- 3В серверной процедуре выполните работу и поместите результат во временное хранилище
- 4В клиентской процедуре-обработчике проверьте статус и заберите результат из хранилища
- 5Покажите пользователю итог или сообщение об ошибке
Способ 4. Обработчик ожидания и периодический опрос
Если серверное событие происходит вне связи с действиями конкретного пользователя (например, пришли данные из обмена), клиент может периодически опрашивать сервер через ПодключитьОбработчикОжидания. Раз в заданный интервал клиент вызывает серверную функцию, проверяет наличие новых данных и реагирует.
Это не самый элегантный способ: каждый опрос — нагрузка на сервер, а реакция запаздывает на величину интервала. Используйте его, когда более современные механизмы недоступны, и выбирайте разумный интервал (не чаще нескольких секунд для интерактивных задач). Не забудьте отключать обработчик при закрытии формы через ОтключитьОбработчикОжидания, иначе получите утечку вызовов.
Способ 5. Система взаимодействия и обсуждения
Если на сервере развёрнута система взаимодействия, доступны уведомления пользователей, которые доставляются клиентским приложениям без постоянного опроса. Серверный код создаёт сообщение или уведомление, а у подключённых пользователей появляется оповещение в панели обсуждений. Интерактивно на него можно отреагировать обработчиком в модуле управляемого приложения.
Этот вариант подходит для межпользовательских сценариев: «менеджеру нужно сообщить, что заказ согласован». Для точечного программного взаимодействия форм он избыточен, а без настроенного сервера системы взаимодействия не работает вовсе — проверяйте доступность механизма перед проектированием на нём.
Сравнение способов
Универсальный вариант, когда клиент сам инициирует действие. Ограничение: работает только синхронно, клиент ждёт ответа.
Подходит для синхронизации открытых форм. Ограничение: работает только внутри одного клиентского сеанса.
Для длительных операций без блокировки интерфейса. Ограничение: результат передаётся через временное хранилище, нужен контроль ошибок.
Для реакции на внешние события. Ограничение: нагрузка на сервер и задержка реакции на интервал опроса.
Для уведомлений между пользователями. Ограничение: требует настроенной инфраструктуры обсуждений.
Типичные ошибки и как их избежать
Наиболее частая ошибка — попытка вызвать процедуру с директивой &НаКлиенте из общего модуля с флагом «Сервер». Конфигуратор отловит это при проверке, но если общий модуль имеет флаги «Клиент» и «Сервер» одновременно, ошибка всплывёт только в рантайме. Разделяйте общие модули по контекстам и не смешивайте вызовы.
Вторая группа ошибок — передача несериализуемых данных между контекстами и игнорирование асинхронной модели. В тонком и веб-клиенте модальные вызовы и синхронные методы ограничены: используйте ПоказатьПредупреждение, ОписаниеОповещения и асинхронные варианты методов вместо устаревших модальных аналогов.
Как проверить результат
Клиент получает структуру с ожидаемыми полями, ошибок нет
Ошибка преобразования данных или пустое значение
ОбработкаОповещения срабатывает в целевой форме, список обновляется
Событие не приходит — проверьте имя события и что форма открыта
Статус «Выполнено», данные читаются из хранилища
Статус «Ошибка» или пустой адрес результата
При отладке помните, что серверный код отлаживается отдельно: включите в конфигураторе отладку на сервере (в том числе «Отладка на сервере» в параметрах), иначе точки останова в серверных процедурах не сработают. Для фоновых заданий включайте отладку фоновых заданий отдельно — это частая причина «неработающих» точек останова.
Что важно запомнить
Сервер не вызывает клиента напрямую — инициатива всегда у клиента. Используйте возврат значений из серверных функций, оповещения форм, фоновые задания с оповещением о завершении, а для внешних событий — опрос или систему взаимодействия. Передавайте между контекстами только сериализуемые данные и минимизируйте число серверных вызовов.
Частые вопросы
Можно ли обойти ограничение и всё-таки вызвать клиентскую процедуру с сервера?
Нет, платформа не предоставляет такого механизма, и обходных путей на уровне встроенного языка не существует. Любая схема сводится к тому, что клиент сам запрашивает сервер или подписывается на событие. Проектируйте логику исходя из этого, а не ищите хак.
Почему Оповестить на сервере недоступно, а ОповеститьОбИзменении — доступно?
Оповестить работает с клиентскими формами текущего сеанса, поэтому это клиентский метод. ОповеститьОбИзменении лишь фиксирует факт изменения данных — платформа сама доставит уведомление клиентским формам при следующем взаимодействии, поэтому метод безопасен для вызова на сервере.
Как передать с сервера на клиент таблицу значений?
Таблица значений сериализуется и может быть возвращена из серверной функции или помещена во временное хранилище. Для больших объёмов предпочтительнее хранилище: сервер кладёт данные через ПоместитьВоВременноеХранилище, клиент забирает по адресу. Учитывайте, что на клиенте с таблицей удобнее работать как с коллекцией строк, а при необходимости отобразить её в форме — преобразовать в данные формы.
Чем отличается ВызватьИсключение на сервере для клиента?
Исключение, возникшее в серверной процедуре, передаётся на клиент как ошибка вызова с текстом причины. Клиентская сторона должна обрабатывать такие ситуации через Попытка/Исключение и показывать пользователю понятное сообщение, а не технический текст. В фоновых заданиях текст ошибки приходит в свойстве результата.
Работает ли обработчик ожидания в веб-клиенте?
Да, ПодключитьОбработчикОжидания поддерживается в веб-клиенте, но каждый срабатывание — это обращение к серверу через браузер. При большом числе пользователей частые опросы создают заметную нагрузку, поэтому интервал стоит выбирать консервативно и отключать обработчик, когда форма не активна.
Как понять, что пора выносить операцию в фоновое задание?
Если серверная операция занимает больше пары секунд, синхронный вызов блокирует интерфейс пользователя. Признаки: «зависшая» форма, жалобы пользователей, таймауты в веб-клиенте. Переносите такую работу в длительную операцию с оповещением о завершении и показывайте индикатор выполнения.