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

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

Как передать данные с сервера на клиент в 1С

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

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

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

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

Что можно и что нельзя передавать между сервером и клиентом

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

Нельзя передать объекты, привязанные к серверному контексту: «Запрос», «РезультатЗапроса», «ВыборкаИзРезультатаЗапроса», «ПостроительОтчета», «СхемаКомпоновкиДанных» в некоторых сценариях, объекты СУБД и COM-объекты, созданные на сервере. Если нужно передать результат запроса — выгрузите его в таблицу значений методом Результат.Выгрузить() и передавайте уже таблицу.

Отдельный случай — данные формы. Реквизиты формы с типами «ДанныеФормыСтруктура», «ДанныеФормыКоллекция» существуют только в контексте формы и передаются между клиентом и сервером автоматически при серверном вызове. Их не нужно сериализовать вручную — платформа делает это сама, но за это приходится платить трафиком: вся форма «ездит» между контекстами при каждом серверном вызове из модуля формы.

Передача через возвращаемое значение серверной функции

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

&НаСервере

Функция ПолучитьОстаткиПоСкладу(Склад)

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ Номенклатура, КоличествоОстаток

|ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &Склад)";

Запрос.УстановитьПараметр("Склад", Склад);

Возврат Запрос.Выполнить().Выгрузить();

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

&НаКлиенте

Процедура ОбновитьОстатки(Команда)

ТаблицаОстатков = ПолучитьОстаткиПоСкладу(ТекущийСклад);

Для Каждого Строка Из ТаблицаОстатков Цикл

// обработка строк на клиенте

КонецЦикла;

КонецПроцедуры

Способ удобен для небольших объёмов — списков, настроек, результатов проверок. Для крупных таблиц (десятки тысяч строк) сериализация и передача по сети заметно замедлят работу, здесь лучше использовать временное хранилище.

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

Типичные ошибки
01
Серверный вызов внутри цикла на клиенте — каждый вызов это сетевой обмен, форма подвисает. Решение: один вызов с пакетной обработкой.
02
Возврат из серверной функции объекта Запрос или ВыборкиИзРезультатаЗапроса — ошибка сериализации. Нужно выгрузить результат в таблицу значений.
03
Использование директивы &НаСервереБезКонтекста с обращением к реквизитам формы — такие процедуры не видят данные формы, ошибка компиляции.

Передача через параметры серверной процедуры

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

&НаСервере

Процедура ЗаполнитьНастройки(Настройки)

Настройки = Новый Структура;

Настройки.Вставить("Организация", ПолучитьОрганизациюПоУмолчанию());

Настройки.Вставить("Валюта", Константы.ВалютаУчета.Получить());

КонецПроцедуры

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

Передача больших данных через временное хранилище

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

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

&НаСервере

Функция ПодготовитьДанныеНаСервере()

Таблица = СформироватьБольшуюТаблицу();

Адрес = ПоместитьВоВременноеХранилище(Таблица, УникальныйИдентификатор);

Возврат Адрес;

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

&НаКлиенте

Процедура ЗагрузитьДанные(Команда)

Адрес = ПодготовитьДанныеНаСервере();

Таблица = ПолучитьИзВременногоХранилища(Адрес);

// работа с таблицей

КонецПроцедуры

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

После извлечения данных, которые больше не нужны, освобождайте хранилище явно методом УдалитьИзВременногоХранилища(Адрес). Это особенно актуально для пакетных обработок, где в цикле создаются десятки адресов.

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

Передача данных из фонового задания на клиент

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

&НаКлиенте

Процедура ЗапуститьЗагрузку(Команда)

АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено, УникальныйИдентификатор);

ПараметрыЗадания = Новый Массив;

ПараметрыЗадания.Добавить(АдресРезультата);

ФоновыеЗадания.Выполнить("ОбменДанными.ЗагрузитьПрайс", ПараметрыЗадания);

// далее — ожидание завершения и чтение результата по АдресРезультата

КонецПроцедуры

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

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

Оповещения: когда сервер должен инициировать передачу

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

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

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

Выбор зависит от объёма данных, частоты обращений и того, кто инициирует обмен. Сводные рекомендации:

СитуацияРекомендуемый способОграничение
Небольшой результат: настройки, список, признакВозвращаемое значение серверной функцииТолько сериализуемые типы
Большая таблица, табличный документВременное хранилищеНужно контролировать срок жизни и удалять данные
Длительная операцияФоновое задание + временное хранилищеНужно отслеживать завершение задания
Уведомление открытых форм об измененииОповестить / ОбработкаОповещенияРаботает только внутри одного сеанса
Данные реквизитов формыАвтоматическая передача платформойКаждый серверный вызов из формы переносит её данные
Контрольные точки

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

Состав возвращаемых данных
Норма

В структуре и таблице только сериализуемые типы: примитивы, ссылки, вложенные коллекции

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

Внутри коллекции объекты Запрос, РезультатЗапроса, COM-объекты — ошибка передачи

Производительность формы
Норма

Один серверный вызов на операцию, форма реагирует быстро

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

Серверные вызовы в цикле, заметные паузы при работе

Память сервера
Норма

Адреса временного хранилища привязаны к форме или удаляются после использования

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

Данные помещаются без идентификатора формы и не удаляются — память растёт

Частые ошибки и их последствия

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

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

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

Итог

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

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

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

Можно ли передать с сервера на клиент картинку или файл?

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

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

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

Чем отличается &НаСервере от &НаСервереБезКонтекста?

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

Как передать данные между двумя открытыми формами?

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

Нужно ли удалять данные из временного хранилища?

Да, если данные помещены без привязки к форме — они живут до конца сеанса. Если при помещении указан уникальный идентификатор формы, платформа удалит данные при её закрытии, но явное удаление через УдалитьИзВременногоХранилища после использования — хорошая практика, особенно в циклах и пакетных обработках.