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

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

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

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

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

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

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

Как устроен обмен между клиентом и сервером

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

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

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

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

Самый прямой способ — объявить функцию в общем модуле с флагом «Сервер» (и при необходимости «Вызов сервера») и передать данные параметрами. Клиентская процедура формирует структуру с данными, вызывает функцию один раз и получает результат.

&НаКлиенте

Процедура РассчитатьНаКлиенте(Команда)

ПараметрыРасчета = Новый Структура;

ПараметрыРасчета.Вставить("Организация", Организация);

ПараметрыРасчета.Вставить("Период", Период);

Результат = РасчетыСервер.ВыполнитьРасчет(ПараметрыРасчета);

ПоказатьПредупреждение(, "Итог: " + Результат);

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

bsl
// Общий модуль РасчетыСервер, флаги: Сервер, Вызов сервера
Функция ВыполнитьРасчет(ПараметрыРасчета) Экспорт
    Запрос = Новый Запрос("ВЫБРАТЬ СУММА(Обороты.Сумма) КАК Итог ИЗ РегистрНакопления.Продажи.Обороты(, &КонецПериода, , Организация = &Организация) КАК Обороты");
    Запрос.УстановитьПараметр("Организация", ПараметрыРасчета.Организация);
    Запрос.УстановитьПараметр("КонецПериода", ПараметрыРасчета.Период);
    Выборка = Запрос.Выполнить().Выбрать();
    Возврат ?(Выборка.Следующий(), Выборка.Итог, 0);
КонецФункции

Ключевое правило: собирайте все нужные серверу данные в одну структуру и делайте один вызов. Цикл с серверным вызовом на каждой итерации — классическая причина «тормозящих» форм: на тысяче строк получится тысяча сетевых обменов вместо одного.

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

Серверные вызовы из формы: контекстные и внеконтекстные

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

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

&НаСервереБезКонтекста

Функция ПолучитьОстатокНаСервере(Номенклатура, Склад)

Запрос = Новый Запрос("ВЫБРАТЬ Остатки.КоличествоОстаток КАК Остаток

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

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

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

Выборка = Запрос.Выполнить().Выбрать();

Возврат ?(Выборка.Следующий(), Выборка.Остаток, 0);

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

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

Контекстный вызов (&НаСервере)

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

Вызов без контекста (&НаСервереБезКонтекста)

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

Общий серверный модуль

Подходит для переиспользуемой логики и вызовов из разных форм. Требует установки флагов «Сервер» и «Вызов сервера».

Передача таблиц значений и сложных коллекций

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

Наиболее надёжный и прозрачный вариант — массив структур. Клиент перебирает строки, складывает их в массив, сервер на своей стороне выгружает массив в таблицу значений или обрабатывает построчно.

&НаКлиенте

Функция ТаблицаВМассивСтруктур(ТаблицаФормы)

Результат = Новый Массив;

Для Каждого Строка Из ТаблицаФормы Цикл

Элемент = Новый Структура("Номенклатура, Количество, Цена");

ЗаполнитьЗначенияСвойств(Элемент, Строка);

Результат.Добавить(Элемент);

КонецЦикла;

Возврат Результат;

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

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

Передача файлов через временное хранилище

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

&НаКлиенте

Процедура ЗагрузитьФайлЗавершение(Результат, Адрес, ВыбранноеИмяФайла, ДопПараметры) Экспорт

Если Результат Тогда

ЗагрузитьНаСервере(Адрес);

КонецЕсли;

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

&НаКлиенте

Процедура ЗагрузитьФайл(Команда)

НачатьПомещениеФайла(Новый ОписаниеОповещения("ЗагрузитьФайлЗавершение", ЭтотОбъект), , , Истина, УникальныйИдентификатор);

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

&НаСервере

Процедура ЗагрузитьНаСервере(АдресХранилища)

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

// дальнейшая обработка: запись в реквизит, разбор XML и т.д.

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

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

Асинхронные вызовы и длительные операции

Серверный вызов блокирует интерфейс клиента: пока сервер считает, форма «висит». Для операций дольше пары секунд платформа предлагает механизм длительных операций: серверный код запускается в фоновом задании (ДлительныеОперации.ВыполнитьВФоне в БСП или ФоновыеЗадания.Выполнить), а клиент периодически опрашивает состояние и показывает индикатор.

Параметры фоновому заданию передаются так же — структурой, которая сериализуется и передаётся на сервер. Результат задание помещает во временное хранилище, откуда клиент забирает его по адресу после завершения. Это тот же связка «параметры + хранилище», только с асинхронным выполнением.

Порядок действий для длительной операции
  1. 1
    Сформируйте на клиенте структуру параметров и вызовите серверную процедуру запуска
  2. 2
    На сервере запустите фоновое задание, передав параметры, и верните клиенту идентификатор и адрес хранилища
  3. 3
    На клиенте подключите обработчик ожидания и периодически проверяйте состояние задания
  4. 4
    После завершения получите результат из временного хранилища по адресу
  5. 5
    Очистите хранилище и обновите данные формы

Типичные ошибки и как их избежать

Самая частая ошибка — серверные вызовы в цикле. Второе место занимает передача несериализуемых типов: попытка передать Запрос, ТаблицаЗначений или объект документа приводит к ошибке вызова. Третья — избыточные контекстные вызовы форм с большими табличными частями, когда достаточно вызова без контекста с двумя параметрами.

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

Типичные ошибки
01
Серверный вызов внутри цикла по строкам — сотни сетевых обменов вместо одного; решение: собрать данные в массив структур и вызвать сервер один раз
02
Передача ТаблицаЗначений или ДокументОбъект параметром — ошибка сериализации; решение: массив структур или создание объекта на сервере
03
Контекстный вызов ради двух значений — на сервер уезжает вся форма с табличными частями; решение: &НаСервереБезКонтекста с явными параметрами
04
Ожидание изменения параметров, переданных без Знач, — при серверном вызове изменения не возвращаются; решение: возвращать результат функцией
05
Накопление данных во временном хранилище без очистки — рост потребления памяти сервера; решение: УдалитьИзВременногоХранилища после использования
Контрольные точки

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

Количество серверных вызовов в обработчике
Норма

Один вызов на действие пользователя

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

Вызовы внутри цикла или цепочка вызовов туда-обратно

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

Примитивы, структуры, массивы, ссылки

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

Запрос, ТаблицаЗначений, объекты документов в параметрах

Поведение формы при расчёте
Норма

Интерфейс отзывчив, длительные операции в фоне с индикатором

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

Форма зависает на несколько секунд без обратной связи

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

Адрес удаляется после получения данных

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

Хранилище накапливается при повторных загрузках

Итог

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

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

FAQ

Можно ли передать таблицу значений с клиента на сервер напрямую?

Нет, тип ТаблицаЗначений не сериализуется в клиентском контексте управляемой формы. Используйте массив структур, реквизит формы табличного типа с контекстным вызовом или сериализацию через ЗначениеВСтрокуВнутр с восстановлением на сервере.

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

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

Что выбрать: контекстный вызов или без контекста?

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

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

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

Как избежать зависания формы при длительном расчёте?

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

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

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