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

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

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

Какие данные передаются между клиентом и сервером 1С: сериализуемые типы, ограничения, мутабельные значения, передача файлов и типичные ошибки разработчиков.

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

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

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

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

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

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

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

Примитивные типы и универсальные коллекции

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

Полностью сериализуемы универсальные коллекции, если их элементы тоже сериализуемы:

  • Массив и ФиксированныйМассив;
  • Структура и ФиксированнаяСтруктура;
  • Соответствие и ФиксированноеСоответствие;
  • СписокЗначений;
  • ТаблицаЗначений и ДеревоЗначений;
  • КлючИЗначение, ОписаниеТипов, Картинка.

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

Отдельно стоит упомянуть ХранилищеЗначения: оно сериализуемо, что позволяет передавать упакованные данные, например сжатые двоичные данные или XML-представления сложных структур.

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

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

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

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

Данные формы и реквизиты формы

В управляемых формах действуют дополнительные правила. Реквизиты формы, имеющие сериализуемые типы, автоматически передаются между клиентом и сервером при каждом серверном вызове в контексте формы (&НаСервере). Это удобно, но таит ловушку производительности: большая таблица значений в реквизите формы будет гоняться по сети туда-обратно при каждом вызове.

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

Для преобразования между объектными типами и данными формы используются методы РеквизитФормыВЗначение() и ЗначениеВРеквизитФормы(), а также ЗначениеВДанныеФормы() и ДанныеФормыВЗначение(). Они работают только на сервере.

Передача файлов и двоичных данных

Файлы между клиентом и сервером передаются через механизм временного хранилища. Прямая передача пути к файлу бессмысленна: путь C:\Документы\файл.xlsx на клиенте не существует на сервере.

Стандартная схема выглядит так:

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

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

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

Что нельзя передавать: полный список ограничений

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

  • Запрос, ПостроительЗапроса, ПостроительОтчёта, СхемаКомпоновкиДанных в виде объекта;
  • COM-объекты и внешние компоненты — они привязаны к процессу, в котором созданы;
  • ЧтениеXML, ЗаписьXML, ЧтениеJSON и другие потоковые объекты;
  • фоновые задания, транзакции, соединения — объекты исполнительного контекста;
  • элементы формы и сама форма как объект.

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

Особого внимания заслуживают мутабельные значения. Структура, переданная на сервер, там изменяется независимо от клиентской копии. Если серверная процедура должна вернуть изменённую коллекцию, её нужно либо возвращать через Возврат, либо передавать параметром без Знач — тогда платформа вернёт изменённое значение на клиент.

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

Оптимизация обмена и проверка результата

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

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

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

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

Тип возвращаемого значения серверной функции
Норма

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

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

ДокументОбъект, Запрос, РезультатЗапроса — вызов завершится ошибкой

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

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

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

Вызов внутри цикла по строкам таблицы

Объём реквизитов формы
Норма

В реквизитах только данные, отображаемые пользователю

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

Большие служебные таблицы, не видимые на форме

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

Итог

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

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

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

Можно ли передать на клиент результат запроса напрямую?

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

Почему изменения структуры на сервере не видны на клиенте?

При передаче создаётся независимая копия значения. Чтобы вернуть изменения, используйте Возврат изменённой структуры или объявите параметр без ключевого слова Знач — тогда платформа передаст изменённое значение обратно на клиент.

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

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

Что быстрее: &НаСервере или &НаСервереБезКонтекста?

Вызов без контекста быстрее, потому что не передаёт данные формы на сервер и обратно. Если процедуре не нужны реквизиты формы, всегда предпочитайте вариант без контекста или выносите логику в серверный общий модуль.

Можно ли передать УникальныйИдентификатор вместо ссылки?

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

Как передать настройки отчёта СКД между клиентом и сервером?

Объект НастройкиКомпоновкиДанных напрямую не передаётся. Сохраните его в ХранилищеЗначения через ЗначениеВХранилище или сериализуйте в XML с помощью СериализаторXDTO, передайте, а на другой стороне восстановите обратно.