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