Какие значения переживают серверный вызов: передача данных между сервером и клиентом в управляемых формах 1С

· 9 мин

Содержание

С сервера на клиент в 1С 8.3 можно передать только значения, которые платформа умеет сериализовать и которые существуют на клиенте: примитивные типы, ссылки на объекты базы, Массив, Структура, Соответствие, СписокЗначений, их фиксированные варианты, ДвоичныеДанные, УникальныйИдентификатор, ТабличныйДокумент и ряд других. ТаблицаЗначений, ДеревоЗначений, Запрос, РезультатЗапроса, выборки, объекты (СправочникОбъект, ДокументОбъект) и наборы записей на тонкий клиент не передаются.

Типичная ситуация: разработчик пишет в форме функцию &НаСервере, возвращает из неё таблицу значений с остатками, а на клиенте получает ошибку времени выполнения. Ниже — что именно проходит через границу «сервер — клиент», как упаковать сложные данные и как не перегрузить канал лишним трафиком. Правила общие для платформы 8.3 и не зависят от конфигурации: БП 3.0, ЗУП 3.1 и УТ 11 работают одинаково.

Как платформа передаёт данные между сервером и клиентом

Каждый вызов серверной процедуры из клиентского кода — это отдельный сетевой запрос. Платформа сериализует параметры, отправляет их на сервер, выполняет код и сериализует обратно возвращаемое значение. На клиент приходит копия данных, а не живой объект: если поменять её на клиенте, на сервере ничего не изменится.

Отсюда три следствия:

  • 📦 тип должен быть сериализуемым — платформа должна уметь превратить его в поток байтов;
  • 🖥️ тип должен быть доступен в контексте клиента — иначе его не во что «распаковать»;
  • 🐢 каждый вызов стоит времени: задержка сети плюс объём данных.

Директивы и что они тащат за собой

ДирективаЧто уходит на серверКогда применять
&НаСерверепараметры и все данные формы (реквизиты, коллекции)нужно читать или менять реквизиты формы
&НаСервереБезКонтекстатолько параметрырасчёт, запрос, проверка, которым форма не нужна
&НаКлиентеНаСервереБезКонтекставызова нет, код выполняется там, где его вызвалиобщие вспомогательные функции

На большой форме с табличной частью на 2000 строк разница между &НаСервере и &НаСервереБезКонтекста заметна на глаз: в первом случае туда и обратно гоняется вся табличная часть.

Параметры без «Знач» возвращаются обратно

Параметры серверной процедуры, объявленные без ключевого слова Знач, после выполнения передаются обратно на клиент — платформа обязана вернуть их возможные изменения. Если массив на 10 000 элементов нужен серверу только для чтения, объявляйте его через Знач:

&НаСервереБезКонтекста
Функция ПосчитатьСумму(Знач МассивСумм)
    Итог = 0;
    Для Каждого Сумма Из МассивСумм Цикл
        Итог = Итог + Сумма;
    КонецЦикла;
    Возврат Итог;
КонецФункции

Чтобы увидеть реальное число серверных вызовов и объём трафика, в Конфигураторе включите отображение показателей производительности в параметрах запуска 1С:Предприятия или запустите клиент с ключом /DisplayPerformance. Внизу окна появится счётчик вызовов и принятых/отправленных данных.

Примитивные типы и простые значения

Эта группа передаётся без ограничений в обе стороны:

  • 🔢 Число — с сохранением точности;
  • 🔤 Строка — любой длины, но длинный текст напрямую увеличивает трафик;
  • 📅 Дата;
  • ✅ Булево;
  • ⭕ Неопределено и Null;
  • 🆔 УникальныйИдентификатор;
  • 🏷️ Тип и ОписаниеТипов.

Проходят и значения оформления: Цвет, Шрифт, Рамка, Картинка, ФорматированнаяСтрока. Их часто формируют на сервере, чтобы раскрасить надпись по итогам проверки.

Отдельно — ТабличныйДокумент. Он доступен на клиенте и передаётся целиком, поэтому типовые печатные формы собираются на сервере и возвращаются на клиент готовым документом. Большой отчёт на сотни страниц — это мегабайты трафика, так что формируйте его на сервере сразу в реквизит формы, а не возвращайте функцией несколько раз подряд.

Ссылки на объекты базы данных

СправочникСсылка, ДокументСсылка, ПеречислениеСсылка, ПланВидовХарактеристикСсылка и другие ссылки передаются на клиент свободно. Ссылка лёгкая: по сути это тип объекта и его идентификатор.

Ограничение в другом. На тонком клиенте нельзя прочитать реквизит через точку:

// На клиенте так не работает:
ИНН = Контрагент.ИНН;

Ссылка есть, а данных объекта у клиента нет. Получить их можно только серверным вызовом. Правильный приём — одна функция без контекста, которая возвращает все нужные реквизиты разом:

&НаСервереБезКонтекста
Функция РеквизитыКонтрагента(Знач Контрагент)
    Возврат Новый Структура("ИНН, КПП, Наименование",
        Контрагент.ИНН, Контрагент.КПП, Контрагент.Наименование);
КонецФункции

Три отдельных вызова за ИНН, КПП и наименованием — это три сетевых запроса вместо одного. В типовых конфигурациях на БСП для этого есть готовые функции модуля ОбщегоНазначения, которые получают значения реквизитов одним запросом; вызывайте их из своей серверной функции.

Сам объект (Контрагент.ПолучитьОбъект()) на клиент не передать. Для редактирования объекта в форме платформа использует ДанныеФормыСтруктура — основной реквизит формы Объект.

Структура и Соответствие как контейнеры для передачи

Структура — главный транспорт между сервером и клиентом. Удобно, когда нужно вернуть несколько значений из одной функции: результат проверки, текст сообщения и ссылку на созданный документ.

&НаСервереБезКонтекста
Функция СоздатьСчет(Знач Заказ)
    Результат = Новый Структура("Успешно, Документ, Сообщение", Ложь, Неопределено, "");
    // ... создание и запись документа ...
    Возврат Результат;
КонецФункции

Соответствие подходит, когда ключи заранее не известны или не являются строками: например, «номенклатура → остаток» для сотни позиций. Ключом может быть ссылка, число или дата.

Правила для обоих контейнеров:

  1. Каждое значение внутри тоже должно быть передаваемым. Одна таблица значений в поле структуры ломает весь вызов.
  2. Ключи структуры — строки, допустимые как идентификаторы: без пробелов и не начинаются с цифры.
  3. Вложенность разрешена: структура в массиве в соответствии — нормально, если на дне только передаваемые типы.

Если клиенту нельзя менять полученные данные, используйте ФиксированнаяСтруктура и ФиксированноеСоответствие. Они тоже передаются и защищают от случайной правки, например, кэшированных настроек.

Таблица значений и список значений: что проходит, а что нет

СписокЗначений доступен на клиенте и передаётся в обе стороны вместе с представлениями и пометками. Его удобно возвращать для выбора из списка: ПоказатьВыборЭлемента работает прямо с ним.

ТаблицаЗначений и ДеревоЗначений существуют только на сервере. Вернуть их функцией на клиент нельзя. Есть три рабочих способа обойти запрет.

Способ 1. Реквизит формы

Создайте реквизит формы типа ТаблицаЗначений с нужными колонками. На клиенте он виден как ДанныеФормыКоллекция, а на сервере заполняется из обычной таблицы:

&НаСервере
Процедура ЗаполнитьОстаткиНаСервере()
    ТЗ = ПолучитьТаблицуОстатков(); // любая серверная функция
    ЗначениеВРеквизитФормы(ТЗ, "Остатки");
КонецПроцедуры

Обратное преобразование — РеквизитФормыВЗначение("Остатки"), тоже только на сервере. Колонки реквизита и таблицы должны совпадать по именам.

Способ 2. Массив структур

Когда таблица нужна клиенту для обработки, а не для показа, превратите строки в структуры:

&НаСервереБезКонтекста
Функция ТаблицаВМассив(Знач Склад)
    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    |    Остатки.Номенклатура КАК Номенклатура,
    |    Остатки.КоличествоОстаток КАК Количество
    |ИЗ
    |    РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &Склад) КАК Остатки";
    Запрос.УстановитьПараметр("Склад", Склад);
    Выборка = Запрос.Выполнить().Выбрать();

    Результат = Новый Массив;
    Пока Выборка.Следующий() Цикл
        Результат.Добавить(Новый Структура("Номенклатура, Количество",
            Выборка.Номенклатура, Выборка.Количество));
    КонецЦикла;
    Возврат Результат;
КонецФункции

Имя регистра здесь условное — подставьте регистр своей конфигурации.

Способ 3. Временное хранилище

Если таблица нужна серверу в следующем вызове, клиенту она вообще не нужна. Положите её во временное хранилище и держите на клиенте только адрес — короткую строку (см. раздел про хранилища ниже).

СпособКогдаМинусы
Реквизит формыданные показываются в таблице на форметребует &НаСервере, гоняет форму целиком
Массив структурклиенту нужны значения для логикилишние имена ключей в каждом элементе увеличивают объём
Временное хранилищеданные нужны только серверу между вызовамихранилище живёт ограниченное время

Массивы, фиксированные массивы и их ограничения

Массив передаётся, если передаваемы все его элементы. Формального предела по числу элементов для передачи нет, но каждый элемент сериализуется и уходит по сети. Массив из 50 000 структур по 10 полей — это уже ощутимая пауза у пользователя на удалённом подключении.

Что проверить, прежде чем возвращать массив:

  • 🔍 нет ли внутри объектов, таблиц, выборок — одна такая запись даёт ошибку на весь массив;
  • ✂️ нужны ли клиенту все колонки; часто хватает ссылки и одного числа;
  • 📄 можно ли отдавать данные порциями, а не все сразу;
  • 🔒 не лучше ли ФиксированныйМассив, если клиент данные только читает.

Не наполняйте массив на клиенте циклом с серверным вызовом на каждый элемент. Сто строк — сто запросов. Соберите параметры в массив на клиенте, отправьте их одним вызовом и получите ответ одним массивом или соответствием.

Хранилище значения, двоичные данные и временное хранилище

Эти три механизма путают, хотя они решают разные задачи.

ХранилищеЗначения

ХранилищеЗначения — тип для хранения в базе произвольного значения, например картинки или настроек. В тонком клиенте этот тип недоступен. Порядок такой: на сервере извлеките содержимое методом Получить() и передайте на клиент результат, если его тип передаваемый, либо положите во временное хранилище.

ДвоичныеДанные

ДвоичныеДанные есть на клиенте и передаются напрямую. Так возвращают файл, сформированный на сервере: выгрузку в XML, архив, PDF. Ограничение одно — размер. Файл на 200 МБ, возвращённый функцией, пройдёт через сериализацию целиком и надолго займёт канал.

Временное хранилище

Для больших и «серверных» данных правильнее временное хранилище:

&НаСервере
Процедура ПодготовитьДанныеНаСервере()
    ТЗ = ПолучитьТаблицуОстатков();
    АдресДанных = ПоместитьВоВременноеХранилище(ТЗ, УникальныйИдентификатор);
КонецПроцедуры

Здесь АдресДанных — строковый реквизит формы, а УникальныйИдентификатор — идентификатор формы: данные живут, пока открыта форма. В следующем серверном вызове таблицу читают через ПолучитьИзВременногоХранилища(АдресДанных).

На клиенте ПолучитьИзВременногоХранилища тоже работает, но вернёт значение только передаваемого типа. Таблицу значений так на клиент не вытащить, а двоичные данные — можно. Для сохранения файла пользователю передайте адрес в метод получения файла с сервера; в новых версиях платформы есть асинхронный ПолучитьФайлССервераАсинх.

Адрес хранилища — строка в несколько десятков символов. Передача адреса вместо данных — самый дешёвый способ «передать» большой объём между вызовами.

Что нельзя передать на клиент и чем заменить

Сводная таблица типов, которые чаще всего пытаются вернуть с сервера:

ТипПочему не передаётсяЧем заменить
ТаблицаЗначений, ДеревоЗначенийнет на клиентереквизит формы, массив структур, временное хранилище
Запрос, РезультатЗапроса, ВыборкаИзРезультатаЗапросасерверные объектывыгрузить нужные поля в массив или структуру
СправочникОбъект, ДокументОбъектживой объект с методами записиДанныеФормыСтруктура (реквизит Объект), структура с реквизитами
РегистрСведенийНаборЗаписей, РегистрСведенийМенеджерЗаписисерверные объектыреквизит формы или массив структур
менеджеры (Справочники.Номенклатура)доступны только на серверевызвать серверную функцию, вернуть результат
ХранилищеЗначениянедоступен в тонком клиентеПолучить() на сервере → передаваемый тип
СхемаКомпоновкиДанныхсерверный объектадрес схемы во временном хранилище

Перечень не полный. Надёжный способ проверить конкретный тип — открыть его в синтаксис-помощнике и посмотреть раздел доступности: если в нём нет тонкого клиента , значение на тонкий клиент не попадёт.

Диагностика: выберите симптом

Частые вопросы

Работают ли эти ограничения в толстом клиенте?
В толстом клиенте в обычном приложении доступно больше типов, в том числе таблица значений. В управляемых формах правила передачи между клиентом и сервером те же, что в тонком клиенте.
Можно ли передать на клиент общий модуль или менеджер?
Нет. Модуль вызывается, а не передаётся. Для серверного общего модуля включите флаг «Вызов сервера» и вызывайте его экспортные функции с клиента.
Сохраняются ли ссылки после передачи?
Да. Ссылка, полученная на клиенте, указывает на тот же объект базы. Её можно вернуть на сервер параметром и прочитать реквизиты там.
Чем ФиксированнаяСтруктура лучше обычной при передаче?
По объёму ничем. Она запрещает изменение на клиенте, поэтому подходит для кэша настроек и констант, которые нельзя случайно испортить.
Почему возврат таблицы значений иногда проходит без ошибки?
Значит, код выполняется в серверном контексте целиком, например внутри общего модуля без вызова с клиента. Ошибка появится, как только значение попытается пересечь границу клиента.