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

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

Какие типы данных можно передавать между клиентом и сервером в 1С

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

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

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

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

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

В управляемом приложении клиентский и серверный код выполняются в разных контекстах. Клиент работает на компьютере пользователя (тонкий, толстый или веб-клиент), сервер — в кластере 1С или в файловом варианте в отдельном серверном контексте. Когда из клиентской процедуры вызывается серверная, платформа упаковывает параметры в передаваемое представление, отправляет их по сети, распаковывает на сервере, выполняет код и возвращает результат тем же способом.

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

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

Примитивные типы и ссылки — базовый минимум

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

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

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

Универсальные коллекции: массивы, структуры, таблицы значений

Универсальные коллекции — основной инструмент передачи составных данных. Сериализуются: Массив, Структура, Соответствие, СписокЗначений, ТаблицаЗначений и ДеревоЗначений. Условие одно: все вложенные элементы тоже должны быть сериализуемыми. Структура, содержащая, например, объект запроса, при передаче вызовет ту же ошибку, что и сам запрос.

Структура — стандартный способ вернуть с сервера набор разнородных данных: признак успеха, текст сообщения, вычисленные значения. Массивы удобны для передачи списков ссылок (например, выделенных документов для групповой обработки). Таблицы значений применяют, когда нужно вернуть на клиент результат выборки, но здесь есть ограничение: в тонком и веб-клиенте таблица значений недоступна как тип реквизита формы напрямую — её обычно преобразуют в ДанныеФормыКоллекция через ЗначениеВДанныеФормы().

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

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

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

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

Отдельно стоит ДвоичныеДанные — тип сериализуем, и это основной способ передачи файлов между клиентом и сервером. Типичный сценарий загрузки файла: клиент помещает файл во временное хранилище (НачатьПомещениеФайла), получает адрес, передаёт адрес на сервер, сервер забирает двоичные данные через ПолучитьИзВременногоХранилища() и обрабатывает. Обратный путь — сервер формирует файл, помещает во временное хранилище и возвращает адрес клиенту.

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

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

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

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

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

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

Особые случаи: XDTO, фиксированные коллекции и мутабельные значения

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

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

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

Маршрут решения

Как выбрать способ передачи

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

Практические приёмы и проверка результата

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

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

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

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

Как проверить результат

Вызов серверной процедуры из тонкого клиента
Норма

Выполняется без ошибок сериализации

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

Ошибка «передача данных между клиентом и сервером»

Состав возвращаемой структуры
Норма

Только примитивы, ссылки и сериализуемые коллекции

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

Вложенные объекты данных, выборки, COM-объекты

Время отклика формы при вызове
Норма

Сопоставимо с временем самой серверной операции

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

Заметная пауза даже при пустом запросе — признак тяжёлой сериализации

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

Все реквизиты сериализуемых типов

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

Форма не открывается или падает при серверном вызове

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

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

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

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

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

Можно ли вернуть с сервера ДокументОбъект, чтобы изменить его на клиенте?

Нет, объектные типы несериализуемы. Правильный подход: передать на сервер ссылку и нужные данные, выполнить изменение и запись объекта целиком на сервере, а на клиент вернуть только результат операции.

Чем отличается передача через временное хранилище от передачи в параметрах?

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

Сохраняются ли типы значений в колонках таблицы значений при передаче?

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

Работает ли передача данных в фоновых заданиях так же?

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

Итог

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

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