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