Какие значения управляемая форма 1С отправляет на сервер, а какие нет
Содержание
С клиента на сервер в 1С 8.3 можно передавать только значения, которые существуют в обоих контекстах и умеют сериализоваться: примитивы (Число, Строка, Дата, Булево, Неопределено, Null), ссылки на объекты базы, значения перечислений, Структура, Массив, Соответствие, СписокЗначений, ДвоичныеДанные, УникальныйИдентификатор, ОписаниеТипов и данные формы. Коллекции передаются, только если внутри у них тоже лежат передаваемые значения.
Нельзя передать ТаблицаЗначений, ДеревоЗначений, Запрос, РезультатЗапроса, объекты вроде ДокументОбъект, наборы записей, саму форму и ОписаниеОповещения. Для них есть обходные пути: ссылка вместо объекта, массив структур вместо таблицы, временное хранилище для больших данных.
Как устроены два контекста управляемого приложения
В управляемом приложении код формы выполняется в двух местах. Тонкий клиент или веб-клиент рисует форму и реагирует на действия пользователя. Сервер 1С:Предприятия работает с базой данных: читает, пишет, проводит.
Каждая процедура модуля формы помечается директивой компиляции:
- 🖥️
&НаКлиенте— выполняется на компьютере пользователя, базы не видит; - 🗄️
&НаСервере— выполняется на сервере, получает копию данных формы; - 📦
&НаСервереБезКонтекста— выполняется на сервере без данных формы, видит только свои параметры; - 🔀
&НаКлиентеНаСервереБезКонтекста— компилируется в обоих местах, работает только с тем, что доступно везде.
Переход с клиента на сервер — это сетевой вызов. Платформа упаковывает параметры, отправляет их, выполняет процедуру и возвращает результат. Поэтому передать можно только то, что получится упаковать и восстановить на другой стороне.
Из общих модулей с клиента доступны только серверные модули с флагом «Вызов сервера». Модуль без этого флага клиентский код просто не видит: при проверке модуля платформа сообщит, что переменная с именем модуля не определена.
Какие типы данных проходят между клиентом и сервером
Общее правило простое: тип должен быть доступен и на клиенте, и на сервере. В синтакс-помощнике это видно в разделе «Доступность» у каждого типа. Если там нет тонкого клиента — значение до клиента не доедет, и обратно тоже.
| Группа | Типы | Особенности |
|---|---|---|
| Примитивы | Число, Строка, Дата, Булево, Неопределено, Null | Передаются всегда |
| Ссылки | СправочникСсылка.*, ДокументСсылка.*, ПеречислениеСсылка.*, ссылки на ПВХ, планы счетов | Уходит только ссылка, без реквизитов объекта |
| Универсальные коллекции | Структура, Массив, Соответствие, СписокЗначений и их фиксированные варианты | Все элементы тоже должны быть передаваемыми |
| Служебные | УникальныйИдентификатор, ОписаниеТипов, Тип, ДвоичныеДанные, СтандартныйПериод | Подходят для ключей и параметров |
| Оформление | ТабличныйДокумент, ФорматированнаяСтрока, Картинка, Цвет, Шрифт | Типично для печатных форм и отчётов |
| Данные формы | ДанныеФормыСтруктура, ДанныеФормыКоллекция, ДанныеФормыДерево | Клиентское представление объектов, таблиц и деревьев |
Ссылка — самый удобный способ указать серверу на объект. Клиент не знает реквизитов справочника, но ссылку держит спокойно. Сервер по ней прочитает всё, что нужно.
Пример: клиент передаёт ссылку на контрагента и получает структуру с нужными полями.
&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
Сведения = СведенияОКонтрагенте(Объект.Контрагент);
Объект.ИНН = Сведения.ИНН;
Объект.КПП = Сведения.КПП;
КонецПроцедуры
&НаСервереБезКонтекста
Функция СведенияОКонтрагенте(Знач Контрагент)
Результат = Новый Структура("ИНН, КПП", "", "");
Если ЗначениеЗаполнено(Контрагент) Тогда
ЗаполнитьЗначенияСвойств(Результат, Контрагент);
КонецЕсли;
Возврат Результат;
КонецФункции
Здесь на клиент уходит Структура из двух строк, а не весь объект справочника. В типовых конфигурациях на БСП то же самое делает функция ОбщегоНазначения.ЗначенияРеквизитовОбъекта.
Что передать нельзя и как обойти запрет
Значения, которые живут только на сервере или только на клиенте, через границу не проходят. Платформа выдаст ошибку в момент вызова, а не при компиляции, поэтому проблема всплывает уже в работе.
Только серверные — на клиент не вернуть:
- ❌
ТаблицаЗначенийиДеревоЗначений; - ❌
Запрос,РезультатЗапроса, выборки,МенеджерВременныхТаблиц; - ❌ объекты:
СправочникОбъект,ДокументОбъект,НаборЗаписей,МенеджерЗаписи; - ❌ схема компоновки данных и прочие серверные механизмы.
Только клиентские — на сервер не отправить:
- ❌ сама форма (
ЭтотОбъектв модуле формы) — в&НаСервереБезКонтекстаеё не передать; - ❌
ОписаниеОповещения— живёт только на клиенте; - ❌
COMОбъект, созданный на клиенте; - ❌ элементы формы (
Элементы.Списоки т. п.).
Ловушка с коллекциями: Структура сама по себе передаётся, но если положить в неё ТаблицаЗначений, вызов упадёт. Платформа проверяет содержимое целиком, на любую глубину вложенности.
Как обойти запрет:
| Что нужно передать | Чем заменить | Когда подходит |
|---|---|---|
| Объект справочника или документа | Ссылку, а на сервере Ссылка.ПолучитьОбъект() | Почти всегда |
| Таблицу значений, небольшую | Массив из Структура, по одной на строку | До нескольких сотен строк |
| Таблицу значений для формы | Реквизит формы типа ТаблицаЗначений и ЗначениеВРеквизитФормы() | Таблицу надо показать пользователю |
| Большой объём данных, файл | Временное хранилище и его адрес-строку | Файлы, выгрузки, тяжёлые отчёты |
| Результат запроса | Массив ссылок или структур, собранный на сервере | Клиенту нужен только список |
В БСП для таблиц есть готовая функция ОбщегоНазначения.ТаблицаЗначенийВМассив: она превращает таблицу в массив структур, который спокойно уходит на клиент.
Как передаются параметры и данные формы при серверном вызове
Здесь кроется главная разница между &НаСервере и &НаСервереБезКонтекста.
При контекстном вызове &НаСервере платформа отправляет на сервер данные формы: реквизит Объект, табличные части, другие реквизиты. На сервере форма собирается заново, процедура работает, и изменённые данные возвращаются на клиент. Чем больше форма, тем дороже вызов.
При вызове &НаСервереБезКонтекста на сервер уходят только параметры процедуры. Никаких данных формы, никаких табличных частей. Это самый лёгкий вызов.
Отдельный момент — модификатор Знач:
- Параметр без
Значпередаётся по ссылке. После серверного вызова его значение возвращается на клиент, даже если сервер его не менял. - Параметр с
Значуходит только в одну сторону. Обратно его копия не возвращается. - Для серверных процедур, которые не должны менять параметр, ставьте
Знач. Это экономит трафик, особенно если параметр — большая структура или массив.
Если серверная функция должна вернуть несколько значений, верните одну Структуру. Это понятнее, чем менять параметры по ссылке, и не гоняет лишние данные.
Внутри &НаСервере с данными формы работают через специальные методы:
- 🔄
РеквизитФормыВЗначение("Объект")— получить настоящийДокументОбъектилиСправочникОбъектиз данных формы; - 🔄
ЗначениеВРеквизитФормы(ДокОбъект, "Объект")— положить объект обратно в форму; - 🔄
ДанныеФормыВЗначение()иЗначениеВДанныеФормы()— то же для произвольных значений и коллекций.
Эти методы есть только на сервере. На клиенте форма видит лишь ДанныеФормыСтруктура и ДанныеФормыКоллекция — урезанные копии без методов записи и проведения.
Глобальный контекст: что доступно на клиенте, а что на сервере
Многие свойства и методы глобального контекста привязаны к одной стороне. Ошибка «метод недоступен на клиенте» — частый спутник переноса кода из обычных форм в управляемые.
| Задача | На клиенте | На сервере |
|---|---|---|
| Получить предопределённое значение | ПредопределенноеЗначение("Справочник.Валюты.Рубль") | Можно и так, и через менеджер Справочники.Валюты.Рубль |
| Спросить пользователя | ПоказатьВопрос, ПоказатьПредупреждение | Недоступно |
| Сообщить пользователю | Сообщение с Новый СообщениеПользователю | Тоже работает: сообщение доедет до клиента |
| Параметры сеанса | Напрямую недоступны | ПараметрыСеанса.Имя |
| Хранить значения на время сеанса | Глобальная ПараметрыПриложения (Соответствие) | Модули повторного использования, параметры сеанса |
| Открыть форму | ОткрытьФорму | Недоступно |
Менеджеры объектов (Справочники, Документы, Перечисления) на тонком клиенте недоступны. Поэтому на клиенте пустую ссылку или предопределённый элемент берут через ПредопределенноеЗначение, а не через Справочники.Валюты.ПустаяСсылка().
Для общих утилит удобно разделение модулей:
- 🧰 клиентский общий модуль — диалоги, оповещения, работа с файлами на компьютере пользователя;
- 🧰 серверный модуль с флагом «Вызов сервера» — точки входа с клиента;
- 🧰 серверный модуль без этого флага — внутренняя логика, с клиента не вызывается;
- 🧰 модуль с флагами «Клиент» и «Сервер» — общие функции, которым не нужна ни база, ни интерфейс (форматирование, проверки строк).
Как сократить число вызовов и защитить данные
Каждый серверный вызов — это сетевой круг. На локальной сети он незаметен. На медленном канале, VPN или веб-клиенте десять вызовов в обработчике превращаются в заметную задержку.
Что реально помогает:
- Собирать данные одним вызовом. Вместо трёх функций «получить ИНН», «получить КПП», «получить адрес» — одна, которая возвращает структуру.
- Предпочитать
&НаСервереБезКонтекста. Контекстный вызов нужен, только если серверу правда нужны данные формы. - Ставить
Значу параметров, которые сервер не меняет. - Кэшировать редко меняющееся. Серверный общий модуль с повторным использованием «На время сеанса» вызывается с клиента один раз, дальше клиент берёт результат из кэша. Возвращайте из таких модулей фиксированные коллекции (
ФиксированнаяСтруктура,ФиксированныйМассив), чтобы результат никто случайно не изменил. - Не таскать файлы через параметры. Помещайте их во временное хранилище: на клиенте — методами помещения файлов, на сервере —
ПоместитьВоВременноеХранилище(). Передавайте только адрес.
Проверить, сколько вызовов делает форма, можно замером производительности в режиме отладки: в Конфигураторе это Отладка → Замер производительности. В результатах видно, какие серверные процедуры вызываются и сколько раз.
С безопасностью правило одно: сервер не доверяет ничему, что пришло с клиента. Модуль с флагом «Вызов сервера» — это открытая дверь, через которую можно передать любые значения.
- 🔒 проверяйте права на сервере, а не скрытием кнопок на форме;
- 🔒 проверяйте тип и заполненность параметров в начале серверной функции;
- 🔒 привилегированный режим включайте только на сервере и только внутри модуля без флага «Вызов сервера»;
- 🔒 не возвращайте на клиент пароли, токены и персональные данные сверх необходимого.
Не делайте общий модуль одновременно «Привилегированным» и «Вызов сервера». Тогда любой пользователь сможет вызвать его функции с любыми параметрами в обход своих прав.
Ошибки при передаче значений и что с ними делать
Почти все проблемы на этой границе сводятся к нескольким сценариям. Ниже — симптомы и куда смотреть.