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