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