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