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