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

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

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

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

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

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

Ниже разобраны рабочие способы передачи значений, ограничения платформы, примеры кода и типичные ошибки, из-за которых данные «теряются» между контекстами.

Как устроен вызов сервера из клиентского кода

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

Директивы компиляции определяют, где выполняется код:

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

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

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

bsl
&НаКлиенте
Процедура КомандаРассчитать(Команда)
	Сумма = РассчитатьНаСервере(Номенклатура, Количество, ДатаОтгрузки);
	ПоказатьОповещениеПользователя("Итог: " + Сумма);
КонецПроцедуры

&НаСервереБезКонтекста
Функция РассчитатьНаСервере(Номенклатура, Количество, ДатаОтгрузки)
	Запрос = Новый Запрос("ВЫБРАТЬ Цена ИЗ РегистрСведений.Цены...");
	// ... обработка
	Возврат Сумма;
КонецФункции

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

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

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

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

bsl
&НаКлиенте
Процедура ОтправитьДанные(Команда)
	ПараметрыДокумента = Новый Структура;
	ПараметрыДокумента.Вставить("Контрагент", Контрагент);
	ПараметрыДокумента.Вставить("Дата", ТекущаяДата());
	ПараметрыДокумента.Вставить("Товары", Новый Массив);
	Для Каждого Строка Из Товары Цикл
		СтрокаТовара = Новый Структура("Номенклатура,Количество,Цена");
		ЗаполнитьЗначенияСвойств(СтрокаТовара, Строка);
		ПараметрыДокумента.Товары.Добавить(СтрокаТовара);
	КонецЦикла;
	СоздатьДокументНаСервере(ПараметрыДокумента);
КонецПроцедуры

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

Типичные ошибки
01
Передача несериализуемых типов (ДокументОбъект, ТабличныйДокумент в некоторых сценариях, COM-объекты) — вызов падает с ошибкой сериализации. Решение: передавать ссылку или примитивные данные.
02
Сбор данных в цикле с серверным вызовом на каждой итерации — десятки сетевых обращений. Решение: собрать всё в структуру или массив и вызвать сервер один раз.
03
Ожидание, что изменения реквизита формы в процедуре &НаСервереБезКонтекста сохранятся — без контекста форма недоступна, изменения теряются.

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

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

Типовой сценарий загрузки файла с клиента на сервер:

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

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

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

Помимо прямых вызовов и хранилища, есть дополнительные механизмы для особых случаев.

Сравнение вариантов

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

Подходит для простых типов, ссылок и небольших структур. Ограничение: только сериализуемые типы, большие объёмы передавать накладно.

Временное хранилище

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

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

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

Фоновые задания (ДлительныеОперации)

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

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

Проверка результата и отладка передачи

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

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

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

Типы параметров на сервере
Норма

Типы совпадают с переданными (ссылка осталась ссылкой, дата — датой)

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

Значения Неопределено или пустые строки — параметр не передан или не сериализовался

Содержимое структур и таблиц
Норма

Все ключи и строки на месте, количество совпадает с клиентским

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

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

Скорость вызова
Норма

Один вызов на всю операцию

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

Вызовы в цикле, заметные паузы интерфейса

Если отладчик на сервере недоступен, используйте ЗаписьЖурналаРегистрации на сервере: зафиксируйте полученные значения и проверьте их в журнале регистрации. Это безопасный способ диагностики, который не останавливает работу пользователей.

Итог

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

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

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

Можно ли передать объект документа (ДокументОбъект) с клиента на сервер?

Нет, объектные типы (ДокументОбъект, СправочникОбъект) не сериализуются между контекстами. Передавайте ссылку на документ, а на сервере получайте объект через Ссылка.ПолучитьОбъект(). Если документ ещё не записан, передавайте его данные в виде структуры и создавайте объект на сервере.

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

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

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

Вызов без контекста быстрее, потому что платформа не сериализует данные формы в обе стороны. Если процедуре не нужны реквизиты формы, всегда используйте &НаСервереБезКонтекста и передавайте нужные значения параметрами.

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

Через временное хранилище: на клиенте поместите файл методом НачатьПомещениеФайлаВХранилище, получите адрес, передайте адрес в серверную процедуру и там извлеките двоичные данные через ПолучитьИзВременногоХранилища. После обработки удалите данные из хранилища.

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

Напрямую — нет, сервер не управляет клиентом. Обратная связь реализуется через возвращаемое значение функции, изменённые параметры по ссылке, оповещения (Оповестить срабатывает уже на клиенте после возврата) или через фоновые задания с опросом состояния на клиенте.

Как передать таблицу значений, если форма недоступна (БезКонтекста)?

Передайте таблицу параметром — ТаблицаЗначений сериализуется. При большом объёме эффективнее поместить её в хранилище на клиенте через ПоместитьВоВременноеХранилище и передать только адрес. Либо преобразуйте таблицу в массив структур, если нужны не все колонки — это сократит объём передачи.