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