Какие значения переживают серверный вызов: передача данных между сервером и клиентом в управляемых формах 1С
Содержание
С сервера на клиент в 1С 8.3 можно передать только значения, которые платформа умеет сериализовать и которые существуют на клиенте: примитивные типы, ссылки на объекты базы, Массив, Структура, Соответствие, СписокЗначений, их фиксированные варианты, ДвоичныеДанные, УникальныйИдентификатор, ТабличныйДокумент и ряд других. ТаблицаЗначений, ДеревоЗначений, Запрос, РезультатЗапроса, выборки, объекты (СправочникОбъект, ДокументОбъект) и наборы записей на тонкий клиент не передаются.
Типичная ситуация: разработчик пишет в форме функцию &НаСервере, возвращает из неё таблицу значений с остатками, а на клиенте получает ошибку времени выполнения. Ниже — что именно проходит через границу «сервер — клиент», как упаковать сложные данные и как не перегрузить канал лишним трафиком. Правила общие для платформы 8.3 и не зависят от конфигурации: БП 3.0, ЗУП 3.1 и УТ 11 работают одинаково.
Как платформа передаёт данные между сервером и клиентом
Каждый вызов серверной процедуры из клиентского кода — это отдельный сетевой запрос. Платформа сериализует параметры, отправляет их на сервер, выполняет код и сериализует обратно возвращаемое значение. На клиент приходит копия данных, а не живой объект: если поменять её на клиенте, на сервере ничего не изменится.
Отсюда три следствия:
- 📦 тип должен быть сериализуемым — платформа должна уметь превратить его в поток байтов;
- 🖥️ тип должен быть доступен в контексте клиента — иначе его не во что «распаковать»;
- 🐢 каждый вызов стоит времени: задержка сети плюс объём данных.
Директивы и что они тащат за собой
| Директива | Что уходит на сервер | Когда применять |
|---|---|---|
&НаСервере | параметры и все данные формы (реквизиты, коллекции) | нужно читать или менять реквизиты формы |
&НаСервереБезКонтекста | только параметры | расчёт, запрос, проверка, которым форма не нужна |
&НаКлиентеНаСервереБезКонтекста | вызова нет, код выполняется там, где его вызвали | общие вспомогательные функции |
На большой форме с табличной частью на 2000 строк разница между &НаСервере и &НаСервереБезКонтекста заметна на глаз: в первом случае туда и обратно гоняется вся табличная часть.
Параметры без «Знач» возвращаются обратно
Параметры серверной процедуры, объявленные без ключевого слова Знач, после выполнения передаются обратно на клиент — платформа обязана вернуть их возможные изменения. Если массив на 10 000 элементов нужен серверу только для чтения, объявляйте его через Знач:
&НаСервереБезКонтекста
Функция ПосчитатьСумму(Знач МассивСумм)
Итог = 0;
Для Каждого Сумма Из МассивСумм Цикл
Итог = Итог + Сумма;
КонецЦикла;
Возврат Итог;
КонецФункции
Чтобы увидеть реальное число серверных вызовов и объём трафика, в Конфигураторе включите отображение показателей производительности в параметрах запуска 1С:Предприятия или запустите клиент с ключом /DisplayPerformance. Внизу окна появится счётчик вызовов и принятых/отправленных данных.
Примитивные типы и простые значения
Эта группа передаётся без ограничений в обе стороны:
- 🔢
Число— с сохранением точности; - 🔤
Строка— любой длины, но длинный текст напрямую увеличивает трафик; - 📅
Дата; - ✅
Булево; - ⭕
НеопределеноиNull; - 🆔
УникальныйИдентификатор; - 🏷️
ТипиОписаниеТипов.
Проходят и значения оформления: Цвет, Шрифт, Рамка, Картинка, ФорматированнаяСтрока. Их часто формируют на сервере, чтобы раскрасить надпись по итогам проверки.
Отдельно — ТабличныйДокумент. Он доступен на клиенте и передаётся целиком, поэтому типовые печатные формы собираются на сервере и возвращаются на клиент готовым документом. Большой отчёт на сотни страниц — это мегабайты трафика, так что формируйте его на сервере сразу в реквизит формы, а не возвращайте функцией несколько раз подряд.
Ссылки на объекты базы данных
СправочникСсылка, ДокументСсылка, ПеречислениеСсылка, ПланВидовХарактеристикСсылка и другие ссылки передаются на клиент свободно. Ссылка лёгкая: по сути это тип объекта и его идентификатор.
Ограничение в другом. На тонком клиенте нельзя прочитать реквизит через точку:
// На клиенте так не работает:
ИНН = Контрагент.ИНН;
Ссылка есть, а данных объекта у клиента нет. Получить их можно только серверным вызовом. Правильный приём — одна функция без контекста, которая возвращает все нужные реквизиты разом:
&НаСервереБезКонтекста
Функция РеквизитыКонтрагента(Знач Контрагент)
Возврат Новый Структура("ИНН, КПП, Наименование",
Контрагент.ИНН, Контрагент.КПП, Контрагент.Наименование);
КонецФункции
Три отдельных вызова за ИНН, КПП и наименованием — это три сетевых запроса вместо одного. В типовых конфигурациях на БСП для этого есть готовые функции модуля ОбщегоНазначения, которые получают значения реквизитов одним запросом; вызывайте их из своей серверной функции.
Сам объект (Контрагент.ПолучитьОбъект()) на клиент не передать. Для редактирования объекта в форме платформа использует ДанныеФормыСтруктура — основной реквизит формы Объект.
Структура и Соответствие как контейнеры для передачи
Структура — главный транспорт между сервером и клиентом. Удобно, когда нужно вернуть несколько значений из одной функции: результат проверки, текст сообщения и ссылку на созданный документ.
&НаСервереБезКонтекста
Функция СоздатьСчет(Знач Заказ)
Результат = Новый Структура("Успешно, Документ, Сообщение", Ложь, Неопределено, "");
// ... создание и запись документа ...
Возврат Результат;
КонецФункции
Соответствие подходит, когда ключи заранее не известны или не являются строками: например, «номенклатура → остаток» для сотни позиций. Ключом может быть ссылка, число или дата.
Правила для обоих контейнеров:
- Каждое значение внутри тоже должно быть передаваемым. Одна таблица значений в поле структуры ломает весь вызов.
- Ключи структуры — строки, допустимые как идентификаторы: без пробелов и не начинаются с цифры.
- Вложенность разрешена: структура в массиве в соответствии — нормально, если на дне только передаваемые типы.
Если клиенту нельзя менять полученные данные, используйте ФиксированнаяСтруктура и ФиксированноеСоответствие. Они тоже передаются и защищают от случайной правки, например, кэшированных настроек.
Таблица значений и список значений: что проходит, а что нет
СписокЗначений доступен на клиенте и передаётся в обе стороны вместе с представлениями и пометками. Его удобно возвращать для выбора из списка: ПоказатьВыборЭлемента работает прямо с ним.
ТаблицаЗначений и ДеревоЗначений существуют только на сервере. Вернуть их функцией на клиент нельзя. Есть три рабочих способа обойти запрет.
Способ 1. Реквизит формы
Создайте реквизит формы типа ТаблицаЗначений с нужными колонками. На клиенте он виден как ДанныеФормыКоллекция, а на сервере заполняется из обычной таблицы:
&НаСервере
Процедура ЗаполнитьОстаткиНаСервере()
ТЗ = ПолучитьТаблицуОстатков(); // любая серверная функция
ЗначениеВРеквизитФормы(ТЗ, "Остатки");
КонецПроцедуры
Обратное преобразование — РеквизитФормыВЗначение("Остатки"), тоже только на сервере. Колонки реквизита и таблицы должны совпадать по именам.
Способ 2. Массив структур
Когда таблица нужна клиенту для обработки, а не для показа, превратите строки в структуры:
&НаСервереБезКонтекста
Функция ТаблицаВМассив(Знач Склад)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Номенклатура КАК Номенклатура,
| Остатки.КоличествоОстаток КАК Количество
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &Склад) КАК Остатки";
Запрос.УстановитьПараметр("Склад", Склад);
Выборка = Запрос.Выполнить().Выбрать();
Результат = Новый Массив;
Пока Выборка.Следующий() Цикл
Результат.Добавить(Новый Структура("Номенклатура, Количество",
Выборка.Номенклатура, Выборка.Количество));
КонецЦикла;
Возврат Результат;
КонецФункции
Имя регистра здесь условное — подставьте регистр своей конфигурации.
Способ 3. Временное хранилище
Если таблица нужна серверу в следующем вызове, клиенту она вообще не нужна. Положите её во временное хранилище и держите на клиенте только адрес — короткую строку (см. раздел про хранилища ниже).
| Способ | Когда | Минусы |
|---|---|---|
| Реквизит формы | данные показываются в таблице на форме | требует &НаСервере, гоняет форму целиком |
| Массив структур | клиенту нужны значения для логики | лишние имена ключей в каждом элементе увеличивают объём |
| Временное хранилище | данные нужны только серверу между вызовами | хранилище живёт ограниченное время |
Массивы, фиксированные массивы и их ограничения
Массив передаётся, если передаваемы все его элементы. Формального предела по числу элементов для передачи нет, но каждый элемент сериализуется и уходит по сети. Массив из 50 000 структур по 10 полей — это уже ощутимая пауза у пользователя на удалённом подключении.
Что проверить, прежде чем возвращать массив:
- 🔍 нет ли внутри объектов, таблиц, выборок — одна такая запись даёт ошибку на весь массив;
- ✂️ нужны ли клиенту все колонки; часто хватает ссылки и одного числа;
- 📄 можно ли отдавать данные порциями, а не все сразу;
- 🔒 не лучше ли
ФиксированныйМассив, если клиент данные только читает.
Не наполняйте массив на клиенте циклом с серверным вызовом на каждый элемент. Сто строк — сто запросов. Соберите параметры в массив на клиенте, отправьте их одним вызовом и получите ответ одним массивом или соответствием.
Хранилище значения, двоичные данные и временное хранилище
Эти три механизма путают, хотя они решают разные задачи.
ХранилищеЗначения
ХранилищеЗначения — тип для хранения в базе произвольного значения, например картинки или настроек. В тонком клиенте этот тип недоступен. Порядок такой: на сервере извлеките содержимое методом Получить() и передайте на клиент результат, если его тип передаваемый, либо положите во временное хранилище.
ДвоичныеДанные
ДвоичныеДанные есть на клиенте и передаются напрямую. Так возвращают файл, сформированный на сервере: выгрузку в XML, архив, PDF. Ограничение одно — размер. Файл на 200 МБ, возвращённый функцией, пройдёт через сериализацию целиком и надолго займёт канал.
Временное хранилище
Для больших и «серверных» данных правильнее временное хранилище:
&НаСервере
Процедура ПодготовитьДанныеНаСервере()
ТЗ = ПолучитьТаблицуОстатков();
АдресДанных = ПоместитьВоВременноеХранилище(ТЗ, УникальныйИдентификатор);
КонецПроцедуры
Здесь АдресДанных — строковый реквизит формы, а УникальныйИдентификатор — идентификатор формы: данные живут, пока открыта форма. В следующем серверном вызове таблицу читают через ПолучитьИзВременногоХранилища(АдресДанных).
На клиенте ПолучитьИзВременногоХранилища тоже работает, но вернёт значение только передаваемого типа. Таблицу значений так на клиент не вытащить, а двоичные данные — можно. Для сохранения файла пользователю передайте адрес в метод получения файла с сервера; в новых версиях платформы есть асинхронный ПолучитьФайлССервераАсинх.
Адрес хранилища — строка в несколько десятков символов. Передача адреса вместо данных — самый дешёвый способ «передать» большой объём между вызовами.
Что нельзя передать на клиент и чем заменить
Сводная таблица типов, которые чаще всего пытаются вернуть с сервера:
| Тип | Почему не передаётся | Чем заменить |
|---|---|---|
ТаблицаЗначений, ДеревоЗначений | нет на клиенте | реквизит формы, массив структур, временное хранилище |
Запрос, РезультатЗапроса, ВыборкаИзРезультатаЗапроса | серверные объекты | выгрузить нужные поля в массив или структуру |
СправочникОбъект, ДокументОбъект | живой объект с методами записи | ДанныеФормыСтруктура (реквизит Объект), структура с реквизитами |
РегистрСведенийНаборЗаписей, РегистрСведенийМенеджерЗаписи | серверные объекты | реквизит формы или массив структур |
менеджеры (Справочники.Номенклатура) | доступны только на сервере | вызвать серверную функцию, вернуть результат |
ХранилищеЗначения | недоступен в тонком клиенте | Получить() на сервере → передаваемый тип |
СхемаКомпоновкиДанных | серверный объект | адрес схемы во временном хранилище |
Перечень не полный. Надёжный способ проверить конкретный тип — открыть его в синтаксис-помощнике и посмотреть раздел доступности: если в нём нет тонкого клиента , значение на тонкий клиент не попадёт.