К статье
Практический материал

Разработка и Конфигурация · 13 мин

Что можно передать с сервера на клиент в 1С: типы данных, ограничения и практика

Разбираем, какие типы данных 1С можно передавать с сервера на клиент: примитивные типы, структуры, сериализуемые объекты и ограничения для ссылок и объектов.

В клиент-серверной архитектуре 1С:Предприятия код выполняется в двух контекстах — на сервере и на клиенте, и между ними постоянно идёт обмен данными. Однако не всё, что существует в серверном контексте, можно просто вернуть в клиентскую процедуру: платформа накладывает жёсткие ограничения на типы передаваемых значений. Незнание этих правил приводит к ошибкам вида «Переданное значение не может быть сериализовано» и к архитектурным просчётам, которые потом дорого исправлять.

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

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

Какие примитивные типы и коллекции передаются без ограничений

Базовый набор типов, которые платформа сериализует автоматически, покрывает большинство практических задач. Это число, строка, дата, булево, тип «Неопределено» и значение NULL. Их можно возвращать из серверных функций и передавать параметрами в любую сторону без дополнительной подготовки.

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

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

Ссылки и объекты: главное различие при передаче

Самая частая ошибка начинающих разработчиков — попытка вернуть с сервера объект типа СправочникОбъект или ДокументОбъект. Эти типы существуют только в серверном контексте: они представляют объект в памяти с возможностью записи в базу данных и не подлежат сериализации. Попытка вернуть такое значение вызывает ошибку передачи данных между клиентом и сервером.

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

Если на клиент нужны данные объекта, а не сама ссылка, соберите их в структуру вручную: прочитайте нужные реквизиты на сервере и положите значения в структуру или таблицу значений. Это единственный корректный способ «передать объект» — фактически передаётся его снимок в виде плоских данных.

Несериализуемые типы: что нельзя вернуть с сервера

Кроме прикладных объектов, существует целый класс серверных типов, которые нельзя передать на клиент ни в каком виде. К ним относятся: Запрос, РезультатЗапроса, ВыборкаИзРезультатаЗапроса, ПостроительЗапроса, ПостроительОтчета, МенеджерВременныхТаблиц, объекты типа ОписаниеТипов в ряде сценариев, а также COM-объекты, OLE-объекты и объекты внешних компонент, созданные на сервере.

Типичная ситуация: разработчик выполняет запрос на сервере и пытается вернуть результат запроса или выборку на клиент. Правильное решение — выгрузить результат в таблицу значений методом Результат.Выгрузить() и передать уже её. Таблица значений сериализуется, хотя для больших объёмов стоит подумать о сокращении состава колонок.

Типичные ошибки
01
Возврат РезультатаЗапроса или Выборки на клиент — вызывает ошибку сериализации; нужно выгрузить результат в таблицу значений
02
Возврат ДокументОбъект вместо ДокументСсылка — объект не сериализуется; на клиент передают ссылку или структуру с данными
03
Передача структуры, внутри которой спрятан несериализуемый тип — ошибка возникает уже на этапе передачи, и найти виновный ключ сложнее; проверяйте вложенность
04
Передача таблицы значений целиком при необходимости в двух колонках — лишний трафик между сервером и клиентом

Хранилище значений и временное хранилище

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

Механика такая: на сервере значение помещается во временное хранилище методом ПоместитьВоВременноеХранилище, который возвращает адрес — строку-идентификатор. Этот адрес передаётся на клиент как обычная строка, а клиент при необходимости забирает данные методом ПолучитьИзВременногоХранилища. Так по каналу связи ходит только короткий адрес, а не сами данные.

В управляемых формах адрес временного хранилища привязан к уникальному идентификатору формы, который передаётся вторым параметром. Без привязки хранилище очищается после завершения серверного вызова, и клиент получит пустоту. Это одна из самых коварных ошибок: код не падает, но данные не приходят.

Передача файла с сервера на клиент через временное хранилище
  1. 1
    На сервере сформируйте данные (двоичные данные, табличный документ, картинку)
  2. 2
    Вызовите ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификаторФормы) и получите адрес
  3. 3
    Верните адрес на клиент как строку — напрямую или в составе структуры результата
  4. 4
    На клиенте вызовите ПолучитьИзВременногоХранилища(Адрес) и обработайте данные
  5. 5
    Проверьте, что данные получены: непустое значение после получения из хранилища

Особенности управляемых форм и реквизитов

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

Таблицы значений в реквизитах формы на клиенте отображаются как ДанныеФормыКоллекция, а дерево значений — как ДанныеФормыДерево. Это обёртки, которые платформа синхронизирует между контекстами автоматически. При программной работе с ними на сервере применяются методы РеквизитФормыВЗначение и ЗначениеВРеквизитФормы.

Директивы компиляции определяют, где выполняется код: &НаСервере, &НаКлиенте, &НаСервереБезКонтекста. Серверные процедуры без контекста не имеют доступа к данным формы напрямую — это удешевляет вызов, так как данные формы не передаются туда-обратно. Для тяжёлых операций, результат которых — небольшая структура, вызов без контекста предпочтительнее.

Способы вернуть данные из серверной процедуры

Возвращаемое значение функции

Подходит для одной структуры или коллекции умеренного размера; ограничение — весь результат сериализуется и передаётся целиком

Параметры процедуры (Знач)

Позволяет вернуть несколько значений через параметры, но усложняет чтение кода; данные также сериализуются

Реквизиты формы

Данные автоматически синхронизируются между клиентом и сервером; подходит для отображаемых данных, но увеличивает трафик при каждом вызове с контекстом

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

Оптимально для больших данных и файлов: по каналу идёт только адрес; требует управления временем жизни хранилища

Производительность: как снизить объём передаваемых данных

Каждый серверный вызов из клиентского кода — это сетевой обмен, и в тонком или веб-клиенте его стоимость заметна. Главный принцип оптимизации: передавать ровно те данные, которые нужны клиенту, и по возможности один вызов вместо нескольких. Если клиенту нужны три набора данных, соберите их в одну структуру на сервере и верните за один вызов.

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

Третий момент — количество вызовов из циклов. Клиентский цикл, внутри которого на каждой итерации вызывается серверная функция, — классическая причина «тормозов» формы. Перенесите цикл целиком на сервер, а на клиент верните итоговый результат.

Контрольные точки

Как проверить качество обмена

Состав возвращаемого значения
Норма

Структура или коллекция содержит только сериализуемые типы и нужные поля

Тревожный признак

Внутри коллекции встречаются объекты, запросы или неиспользуемые колонки

Количество серверных вызовов
Норма

Один вызов на логическую операцию, циклы выполняются на сервере

Тревожный признак

Серверные вызовы внутри клиентского цикла

Работа с временным хранилищем
Норма

Адрес привязан к идентификатору формы, данные получаются на клиенте

Тревожный признак

После получения из хранилища приходит Неопределено

Поведение при ошибке
Норма

Функция возвращает структуру с признаком ошибки и текстом

Тревожный признак

Исключение на сервере обрывает клиентский сценарий без диагностики

Практический пример: функция возврата данных на клиент

Типовая серверная функция, которая собирает данные для клиента, выглядит как сборка структуры результата. Ниже показан каркас такой функции с соблюдением правил сериализации:

Функция ПолучитьДанныеДокумента(ДокументСсылка) Экспорт

Результат = Новый Структура;

Результат.Вставить("Успех", Ложь);

Результат.Вставить("СообщениеОбОшибке", "");

Результат.Вставить("Реквизиты", Новый Структура);

Результат.Вставить("ТабличнаяЧасть", Новый Массив);

Попытка

Запрос = Новый Запрос("ВЫБРАТЬ ...");

// заполнение Результат.Реквизиты примитивами

// и Результат.ТабличнаяЧасть массивом структур

Результат.Успех = Истина;

Исключение

Результат.СообщениеОбОшибке = ОписаниеОшибки();

КонецПопытки;

Возврат Результат;

КонецФункции

Обратите внимание на ключевые решения: функция принимает ссылку (сериализуемый тип), работает с запросом только внутри сервера, а наружу отдаёт структуру с примитивами и массивом структур. Клиентский код проверяет флаг «Успех» и либо использует данные, либо показывает пользователю текст ошибки. Такой контракт устойчив к изменениям: новые поля добавляются в структуру без ломки вызовов.

При передаче дат между сервером и клиентом учитывайте, что сеансовый часовой пояс сервера и клиента может различаться. Если логика зависит от точного времени, передавайте дату в универсальном формате или явно оговаривайте, в каком поясе она сформирована.
ПЗ
Практическое замечание

Частые вопросы о передаче данных между сервером и клиентом

Можно ли передать с сервера на клиент табличный документ?

Табличный документ сериализуется и может быть передан, однако для больших макетов эффективнее поместить его во временное хранилище и вернуть на клиент адрес. Так по каналу связи передаётся только строка-идентификатор, а сам документ клиент заберёт при необходимости.

Почему возникает ошибка «значение не может быть сериализовано»?

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

Можно ли вызвать серверную процедуру общего модуля с клиента?

Да, если у общего модуля установлены флаги «Сервер» и «Вызов сервера». Процедура должна быть экспортной. Параметры и возвращаемое значение подчиняются стандартным правилам сериализации. Модули с флагом «Привилегированный режим» выполняются без проверки прав, что важно учитывать при проектировании.

Что выбрать: реквизит формы или временное хранилище?

Реквизит формы подходит для данных, которые отображаются и редактируются в форме постоянно. Временное хранилище — для разовой передачи больших данных: файлов, отчётов, картинок. Хранить большие данные в реквизите формы не стоит: они будут передаваться при каждом серверном вызове с контекстом.

Передаются ли между контекстами значения перечислений?

Да, значения перечислений являются ссылочным типом и сериализуются без ограничений. Их можно передавать как отдельными значениями, так и в составе структур, массивов и таблиц значений.

Как передать картинку с сервера на клиент?

Загрузите картинку на сервере (из хранилища значений в базе или из файла), поместите двоичные данные или объект Картинка во временное хранилище с привязкой к идентификатору формы и верните адрес. На клиенте адрес можно назначить реквизиту формы, отображающему картинку, или получить данные программно.

Итог

Что важно запомнить

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