Разработка и Конфигурация · 13 мин
Что можно передать с сервера на клиент в 1С: типы данных, ограничения и практика
Разбираем, какие типы данных 1С можно передавать с сервера на клиент: примитивные типы, структуры, сериализуемые объекты и ограничения для ссылок и объектов.
В клиент-серверной архитектуре 1С:Предприятия код выполняется в двух контекстах — на сервере и на клиенте, и между ними постоянно идёт обмен данными. Однако не всё, что существует в серверном контексте, можно просто вернуть в клиентскую процедуру: платформа накладывает жёсткие ограничения на типы передаваемых значений. Незнание этих правил приводит к ошибкам вида «Переданное значение не может быть сериализовано» и к архитектурным просчётам, которые потом дорого исправлять.
Передача данных между контекстами происходит через сериализацию: платформа упаковывает значение во внутреннее представление, пересылает его по каналу связи и восстанавливает на другой стороне. Поэтому ключевой критерий — сериализуемость типа. Примитивы, коллекции и ссылки сериализуются без проблем, а объекты, привязанные к серверному состоянию (запросы, менеджеры временных таблиц, объекты метаданных), — нет.
Отдельная сложность — управляемые формы. Данные формы хранятся в особом виде, и передача между сервером и клиентом выполняется через реквизиты формы с учётом их типов. Понимание того, что и как можно вернуть из серверной процедуры, позволяет проектировать обмен минимальным объёмом данных и избегать лишних серверных вызовов.
Какие примитивные типы и коллекции передаются без ограничений
Базовый набор типов, которые платформа сериализует автоматически, покрывает большинство практических задач. Это число, строка, дата, булево, тип «Неопределено» и значение NULL. Их можно возвращать из серверных функций и передавать параметрами в любую сторону без дополнительной подготовки.
Поверх примитивов работают универсальные коллекции: массив, структура, соответствие, список значений, таблица значений, дерево значений и фиксированные варианты этих коллекций. Важно, что коллекции могут быть вложенными — например, массив структур, каждая из которых содержит таблицу значений. Ограничение одно: все вложенные элементы тоже должны быть сериализуемыми типами.
Практический приём — упаковка результата серверной обработки в структуру с заранее согласованным набором ключей. Например, функция возвращает структуру с полями «Успех», «СообщениеОбОшибке», «Данные». Такой контракт делает клиентский код предсказуемым и упрощает отладку: на клиенте всегда известно, какие ключи проверять.
Ссылки и объекты: главное различие при передаче
Самая частая ошибка начинающих разработчиков — попытка вернуть с сервера объект типа СправочникОбъект или ДокументОбъект. Эти типы существуют только в серверном контексте: они представляют объект в памяти с возможностью записи в базу данных и не подлежат сериализации. Попытка вернуть такое значение вызывает ошибку передачи данных между клиентом и сервером.
При этом ссылки — СправочникСсылка, ДокументСсылка, ПеречислениеСсылка и другие ссылочные типы — передаются свободно. Ссылка — это лёгкий идентификатор объекта, и на клиенте через неё доступны реквизиты, которые платформа дочитает из базы автоматически. Поэтому правильный паттерн: на сервере работаем с объектами, на клиент возвращаем ссылки и примитивные данные.
Если на клиент нужны данные объекта, а не сама ссылка, соберите их в структуру вручную: прочитайте нужные реквизиты на сервере и положите значения в структуру или таблицу значений. Это единственный корректный способ «передать объект» — фактически передаётся его снимок в виде плоских данных.
Несериализуемые типы: что нельзя вернуть с сервера
Кроме прикладных объектов, существует целый класс серверных типов, которые нельзя передать на клиент ни в каком виде. К ним относятся: Запрос, РезультатЗапроса, ВыборкаИзРезультатаЗапроса, ПостроительЗапроса, ПостроительОтчета, МенеджерВременныхТаблиц, объекты типа ОписаниеТипов в ряде сценариев, а также COM-объекты, OLE-объекты и объекты внешних компонент, созданные на сервере.
Типичная ситуация: разработчик выполняет запрос на сервере и пытается вернуть результат запроса или выборку на клиент. Правильное решение — выгрузить результат в таблицу значений методом Результат.Выгрузить() и передать уже её. Таблица значений сериализуется, хотя для больших объёмов стоит подумать о сокращении состава колонок.
Хранилище значений и временное хранилище
Для передачи больших или бинарных данных — картинок, файлов, макетов — используется тип ХранилищеЗначения. Оно сериализуется, но передавать его напрямую между контекстами неэффективно: данные будут гоняться по каналу при каждом вызове. Правильный инструмент здесь — временное хранилище.
Механика такая: на сервере значение помещается во временное хранилище методом ПоместитьВоВременноеХранилище, который возвращает адрес — строку-идентификатор. Этот адрес передаётся на клиент как обычная строка, а клиент при необходимости забирает данные методом ПолучитьИзВременногоХранилища. Так по каналу связи ходит только короткий адрес, а не сами данные.
В управляемых формах адрес временного хранилища привязан к уникальному идентификатору формы, который передаётся вторым параметром. Без привязки хранилище очищается после завершения серверного вызова, и клиент получит пустоту. Это одна из самых коварных ошибок: код не падает, но данные не приходят.
- 1На сервере сформируйте данные (двоичные данные, табличный документ, картинку)
- 2Вызовите ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификаторФормы) и получите адрес
- 3Верните адрес на клиент как строку — напрямую или в составе структуры результата
- 4На клиенте вызовите ПолучитьИзВременногоХранилища(Адрес) и обработайте данные
- 5Проверьте, что данные получены: непустое значение после получения из хранилища
Особенности управляемых форм и реквизитов
В управляемых формах обмен между сервером и клиентом идёт через реквизиты формы. При серверном вызове платформа передаёт на сервер данные формы, а после выполнения — возвращает изменения обратно. Типы реквизитов формы ограничены тем же правилом сериализуемости: нельзя добавить реквизит типа ДокументОбъект, но можно — ДокументСсылка, таблицу значений или динамический список.
Таблицы значений в реквизитах формы на клиенте отображаются как ДанныеФормыКоллекция, а дерево значений — как ДанныеФормыДерево. Это обёртки, которые платформа синхронизирует между контекстами автоматически. При программной работе с ними на сервере применяются методы РеквизитФормыВЗначение и ЗначениеВРеквизитФормы.
Директивы компиляции определяют, где выполняется код: &НаСервере, &НаКлиенте, &НаСервереБезКонтекста. Серверные процедуры без контекста не имеют доступа к данным формы напрямую — это удешевляет вызов, так как данные формы не передаются туда-обратно. Для тяжёлых операций, результат которых — небольшая структура, вызов без контекста предпочтительнее.
Способы вернуть данные из серверной процедуры
Подходит для одной структуры или коллекции умеренного размера; ограничение — весь результат сериализуется и передаётся целиком
Позволяет вернуть несколько значений через параметры, но усложняет чтение кода; данные также сериализуются
Данные автоматически синхронизируются между клиентом и сервером; подходит для отображаемых данных, но увеличивает трафик при каждом вызове с контекстом
Оптимально для больших данных и файлов: по каналу идёт только адрес; требует управления временем жизни хранилища
Производительность: как снизить объём передаваемых данных
Каждый серверный вызов из клиентского кода — это сетевой обмен, и в тонком или веб-клиенте его стоимость заметна. Главный принцип оптимизации: передавать ровно те данные, которые нужны клиенту, и по возможности один вызов вместо нескольких. Если клиенту нужны три набора данных, соберите их в одну структуру на сервере и верните за один вызов.
Второй принцип — не гонять лишние колонки и строки. Таблица значений с двадцатью колонками, из которых клиент использует пять, — это прямой перерасход трафика. Сформируйте на сервере усечённую таблицу или массив структур только с нужными полями. Для больших выборок рассмотрите порционную передачу или отображение через динамический список, который платформа читает постранично.
Третий момент — количество вызовов из циклов. Клиентский цикл, внутри которого на каждой итерации вызывается серверная функция, — классическая причина «тормозов» формы. Перенесите цикл целиком на сервер, а на клиент верните итоговый результат.
Как проверить качество обмена
Структура или коллекция содержит только сериализуемые типы и нужные поля
Внутри коллекции встречаются объекты, запросы или неиспользуемые колонки
Один вызов на логическую операцию, циклы выполняются на сервере
Серверные вызовы внутри клиентского цикла
Адрес привязан к идентификатору формы, данные получаются на клиенте
После получения из хранилища приходит Неопределено
Функция возвращает структуру с признаком ошибки и текстом
Исключение на сервере обрывает клиентский сценарий без диагностики
Практический пример: функция возврата данных на клиент
Типовая серверная функция, которая собирает данные для клиента, выглядит как сборка структуры результата. Ниже показан каркас такой функции с соблюдением правил сериализации:
Функция ПолучитьДанныеДокумента(ДокументСсылка) Экспорт
Результат = Новый Структура;
Результат.Вставить("Успех", Ложь);
Результат.Вставить("СообщениеОбОшибке", "");
Результат.Вставить("Реквизиты", Новый Структура);
Результат.Вставить("ТабличнаяЧасть", Новый Массив);
Попытка
Запрос = Новый Запрос("ВЫБРАТЬ ...");
// заполнение Результат.Реквизиты примитивами
// и Результат.ТабличнаяЧасть массивом структур
Результат.Успех = Истина;
Исключение
Результат.СообщениеОбОшибке = ОписаниеОшибки();
КонецПопытки;
Возврат Результат;
КонецФункции
Обратите внимание на ключевые решения: функция принимает ссылку (сериализуемый тип), работает с запросом только внутри сервера, а наружу отдаёт структуру с примитивами и массивом структур. Клиентский код проверяет флаг «Успех» и либо использует данные, либо показывает пользователю текст ошибки. Такой контракт устойчив к изменениям: новые поля добавляются в структуру без ломки вызовов.
При передаче дат между сервером и клиентом учитывайте, что сеансовый часовой пояс сервера и клиента может различаться. Если логика зависит от точного времени, передавайте дату в универсальном формате или явно оговаривайте, в каком поясе она сформирована.
Частые вопросы о передаче данных между сервером и клиентом
Можно ли передать с сервера на клиент табличный документ?
Табличный документ сериализуется и может быть передан, однако для больших макетов эффективнее поместить его во временное хранилище и вернуть на клиент адрес. Так по каналу связи передаётся только строка-идентификатор, а сам документ клиент заберёт при необходимости.
Почему возникает ошибка «значение не может быть сериализовано»?
Ошибка означает, что в возвращаемом значении или параметре есть несериализуемый тип: объект данных, запрос, результат запроса, выборка или COM-объект. Проверьте не только верхний уровень, но и вложенные элементы структур и массивов — несериализуемое значение часто прячется внутри коллекции.
Можно ли вызвать серверную процедуру общего модуля с клиента?
Да, если у общего модуля установлены флаги «Сервер» и «Вызов сервера». Процедура должна быть экспортной. Параметры и возвращаемое значение подчиняются стандартным правилам сериализации. Модули с флагом «Привилегированный режим» выполняются без проверки прав, что важно учитывать при проектировании.
Что выбрать: реквизит формы или временное хранилище?
Реквизит формы подходит для данных, которые отображаются и редактируются в форме постоянно. Временное хранилище — для разовой передачи больших данных: файлов, отчётов, картинок. Хранить большие данные в реквизите формы не стоит: они будут передаваться при каждом серверном вызове с контекстом.
Передаются ли между контекстами значения перечислений?
Да, значения перечислений являются ссылочным типом и сериализуются без ограничений. Их можно передавать как отдельными значениями, так и в составе структур, массивов и таблиц значений.
Как передать картинку с сервера на клиент?
Загрузите картинку на сервере (из хранилища значений в базе или из файла), поместите двоичные данные или объект Картинка во временное хранилище с привязкой к идентификатору формы и верните адрес. На клиенте адрес можно назначить реквизиту формы, отображающему картинку, или получить данные программно.
Что важно запомнить
С сервера на клиент передаются примитивные типы, коллекции, ссылки и сериализуемые таблицы; объекты данных, запросы и результаты запросов передавать нельзя — их заменяют ссылками, структурами и выгрузками в таблицы значений. Для больших данных используйте временное хранилище с привязкой к форме, а для снижения нагрузки объединяйте данные в один серверный вызов и передавайте только нужные поля.