Передача данных объекта из формы и внешней системы на сервер 1С

· 10 мин

Содержание

Сам объект (ДокументОбъект, СправочникОбъект) с клиента на сервер 1С не передаётся: на тонком клиенте его просто нет. Передают данные объекта. Внутри формы это структура, ссылка или реквизит формы, который сервер превращает в объект через РеквизитФормыВЗначение(). Из внешней системы это JSON или XML, который принимает HTTP-сервис или Web-сервис, а сервер уже сам создаёт и записывает объект.

Ниже оба случая: обмен клиент–сервер внутри одной базы и передача объекта из другой программы или другой базы. С кодом, проверками и настройкой доступа.

Где ваш «клиент»: форма 1С или внешняя программа

Вопрос «как передать объект на сервер» задают в двух разных ситуациях. От ответа зависит весь инструмент.

  • 🖥️ Клиент внутри 1С. Процедура формы с директивой &НаКлиенте должна отдать данные в &НаСервере. Сеть, протоколы и форматы тут не нужны: платформа сама передаёт значения при серверном вызове. Задача — выбрать передаваемый тип.
  • 🌐 Внешний клиент. Сайт, мобильное приложение, сервис на Python или другая база 1С отправляет данные на сервер 1С. Здесь нужен протокол (HTTP, SOAP, COM), формат (JSON, XML) и аутентификация.

Если коротко: в первом случае вы пишете два метода в модуле формы, во втором — публикуете сервис на веб-сервере.

Как передать данные объекта из формы на сервер

На клиенте доступны не все типы. Между &НаКлиенте и &НаСервере свободно ходят:

  • примитивы: Строка, Число, Дата, Булево, Неопределено;
  • ссылки: ДокументСсылка.*, СправочникСсылка.*;
  • коллекции: Структура, Массив, Соответствие и их фиксированные варианты;
  • ДвоичныеДанные, УникальныйИдентификатор;
  • данные формы: реквизиты формы, в том числе основной реквизит Объект.

Не передаются объекты прикладных типов, ТаблицаЗначений, Запрос, МенеджерВременныхТаблиц. Попытка вернуть их с сервера на клиент даёт ошибку о том, что тип нельзя передать.

Способ 1. Структура в серверный метод без контекста

Самый лёгкий вызов. Форма не уходит на сервер целиком, передаются только нужные поля.

&НаКлиенте
Процедура СоздатьЗаказ(Команда)
	Данные = Новый Структура;
	Данные.Вставить("Контрагент", Объект.Контрагент);
	Данные.Вставить("Сумма", 1500);
	Данные.Вставить("Комментарий", "Заказ с формы");
	НовыйЗаказ = СоздатьЗаказНаСервере(Данные);
	ПоказатьЗначение(, НовыйЗаказ);
КонецПроцедуры

&НаСервереБезКонтекста
Функция СоздатьЗаказНаСервере(Данные)
	ДокОбъект = Документы.ЗаказКлиента.СоздатьДокумент();
	ЗаполнитьЗначенияСвойств(ДокОбъект, Данные);
	ДокОбъект.Дата = ТекущаяДатаСеанса();
	ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
	Возврат ДокОбъект.Ссылка;
КонецФункции

ЗаполнитьЗначенияСвойств перенесёт поля, имена которых совпадают с реквизитами документа. Обратно на клиент уходит ссылка, а не объект.

&НаСервереБезКонтекста не тащит на сервер данные формы. При частых вызовах это заметно экономит трафик и время, особенно на медленном канале.

Способ 2. Реквизит формы → объект → реквизит формы

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

&НаСервере
Процедура ПересчитатьНаСервере()
	ДокОбъект = РеквизитФормыВЗначение("Объект");
	ДокОбъект.ПересчитатьСуммы(); // экспортная процедура модуля объекта
	ЗначениеВРеквизитФормы(ДокОбъект, "Объект");
КонецПроцедуры

Здесь вызов идёт с контекстом: форма передаётся на сервер, там превращается в настоящий объект, а результат возвращается в форму. Записи в базу при этом нет, пока пользователь не нажмёт «Записать».

Вне формы, например в общем модуле, используют ДанныеФормыВЗначение(Данные, Тип("ДокументОбъект.ЗаказКлиента")) и обратную ЗначениеВДанныеФормы().

Способ 3. Временное хранилище для больших данных

Файл, картинку или большой массив передают через временное хранилище. На клиенте кладут значение и получают адрес, на сервер отправляют только строку адреса.

&НаКлиенте
Процедура ОтправитьФайл(ДвоичныеДанныеФайла)
	Адрес = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, УникальныйИдентификатор);
	ЗагрузитьНаСервере(Адрес);
КонецПроцедуры

&НаСервере
Процедура ЗагрузитьНаСервере(Адрес)
	Данные = ПолучитьИзВременногоХранилища(Адрес);
	УдалитьИзВременногоХранилища(Адрес);
	// разбор и запись данных
КонецПроцедуры

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

Каким каналом передать объект во внешнюю базу 1С

Если клиент — внешняя система, выбирают протокол. Варианты у платформы 8.3 такие.

КаналФорматКогда выбиратьОграничения
HTTP-сервисJSON, XML, любойREST-интеграции: сайт, мобильное приложение, Python, другая 1ССхему данных описываете и проверяете сами
Web-сервис (SOAP)XML по пакету XDTOСтрогий контракт, интеграция с корпоративной шиной, Java/.NET-клиентыТяжелее в настройке, больше объём сообщений
Стандартный интерфейс ODataJSON, AtomНужно быстро открыть чтение и запись типовых объектов без программированияБизнес-логику не добавить, нужна настройка состава объектов
COM-соединениеЗначения через COMДве базы на одном Windows-сервере, разовые обработкиТолько Windows, совпадение версий comcntr.dll, не для веба

Для новой интеграции чаще всего берут HTTP-сервис. Он прост для внешних разработчиков: обычный POST с JSON, ответ с кодом состояния.

Web-сервис оправдан, когда заказчик требует WSDL и проверку сообщения по схеме ещё до вашего кода.

COM-соединение (Новый COMОбъект("V83.COMConnector")) удобно для обработки, которая из одной базы пишет в другую на том же сервере. Объект чужой базы напрямую в свою не передать: передают строки и числа или сериализуют данные в XML-строку.

JSON или XML: сериализация объекта 1С

Перед отправкой объект превращают в текст. Есть два подхода.

Свой формат. Вы собираете Структуру с нужными полями и пишете её в JSON. Внешняя система получает понятный документ без служебных полей 1С. Ссылки заменяете на коды, ИНН или GUID.

Функция ЗаказВJSON(ДокОбъект)
	Данные = Новый Структура;
	Данные.Вставить("id", Строка(ДокОбъект.Ссылка.УникальныйИдентификатор()));
	Данные.Вставить("number", ДокОбъект.Номер);
	Данные.Вставить("date", XMLСтрока(ДокОбъект.Дата));
	Данные.Вставить("inn", ДокОбъект.Контрагент.ИНН);
	Данные.Вставить("sum", ДокОбъект.СуммаДокумента);
	Запись = Новый ЗаписьJSON;
	Запись.УстановитьСтроку();
	ЗаписатьJSON(Запись, Данные);
	Возврат Запись.Закрыть();
КонецФункции

Дату лучше отдавать через XMLСтрока(): получится формат 2026-10-07T00:00:00, который поймёт любой парсер.

Сериализатор XDTO. Глобальный СериализаторXDTO пишет объект целиком: все реквизиты и табличные части, ссылки — в виде GUID. Подходит для обмена 1С ↔ 1С с одинаковой структурой метаданных.

Запись = Новый ЗаписьXML;
Запись.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(Запись, ДокОбъект);
ТекстXML = Запись.Закрыть();

На приёмной стороне СериализаторXDTO.ПрочитатьXML(ЧтениеXML) вернёт готовый объект, который остаётся записать. Есть и вариант в JSON — метод ЗаписатьJSON у того же сериализатора.

КритерийСвой JSONXDTO (XML или JSON)
ПолучательЛюбая системаТолько 1С с той же конфигурацией
ОбъёмМинимальныйБольшой, все поля
Устойчивость к изменениямВысокая, вы контролируете поляЛомается при расхождении метаданных
ТрудозатратыНужно описать поляОдна строка кода

Настройка HTTP-сервиса, который принимает объект

Порядок в конфигураторе.

  1. В дереве конфигурации откройте Общие → HTTP-сервисы и добавьте сервис, например Orders. Укажите корневой URL — orders.
  2. Добавьте шаблон URL, например /doc, а в нём метод с HTTP-методом POST.
  3. В свойствах метода нажмите на лупу у поля «Обработчик» — платформа создаст функцию в модуле сервиса.
  4. Опубликуйте базу: Администрирование → Публикация на веб-сервере, отметьте флаг публикации HTTP-сервисов и нужный сервис.
  5. Адрес для клиента: https://сервер/имя_публикации/hs/orders/doc.

Пример обработчика, который принимает JSON и создаёт или обновляет заказ:

Функция DocPOST(Запрос)
	Попытка
		Чтение = Новый ЧтениеJSON;
		Чтение.УстановитьСтроку(Запрос.ПолучитьТелоКакСтроку());
		Данные = ПрочитатьJSON(Чтение, Истина); // Соответствие
		Чтение.Закрыть();
	Исключение
		Возврат ОтветJSON(400, "Тело запроса не является JSON");
	КонецПопытки;

	Попытка
		Ид = Новый УникальныйИдентификатор(Данные.Получить("id"));
	Исключение
		Возврат ОтветJSON(400, "Поле id должно содержать GUID");
	КонецПопытки;

	Ссылка = Документы.ЗаказКлиента.ПолучитьСсылку(Ид);
	ДокОбъект = Ссылка.ПолучитьОбъект();
	Если ДокОбъект = Неопределено Тогда
		ДокОбъект = Документы.ЗаказКлиента.СоздатьДокумент();
		ДокОбъект.УстановитьСсылкуНового(Ссылка);
		ДокОбъект.Дата = ТекущаяДатаСеанса();
	КонецЕсли;
	ДокОбъект.Комментарий = Данные.Получить("comment");
	// заполнение остальных реквизитов и табличной части

	Возврат ЗаписатьЗаказ(ДокОбъект);
КонецФункции

Функция ОтветJSON(Код, Текст)
	Запись = Новый ЗаписьJSON;
	Запись.УстановитьСтроку();
	ЗаписатьJSON(Запись, Новый Структура("code, message", Код, Текст));
	Ответ = Новый HTTPСервисОтвет(Код);
	Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
	Ответ.УстановитьТелоИзСтроки(Запись.Закрыть(), КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
	Возврат Ответ;
КонецФункции

Параметр Истина в ПрочитатьJSON возвращает Соответствие. С ним не упадёт ключ, который не годится в имя свойства структуры: order-id, 1c_code и подобные.

GUID от внешней системы плюс УстановитьСсылкуНового() делают приём идемпотентным. Повторная отправка того же заказа обновит документ, а не создаст дубль.

Со стороны другой базы 1С отправка выглядит так:

Соединение = Новый HTTPСоединение("server.example.ru", 443, "Обмен", Пароль, , 30, Новый ЗащищенноеСоединениеOpenSSL);
Запрос = Новый HTTPЗапрос("/trade/hs/orders/doc");
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Запрос.УстановитьТелоИзСтроки(ЗаказВJSON(ДокОбъект), КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния <> 200 Тогда
	ВызватьИсключение Ответ.ПолучитьТелоКакСтроку();
КонецЕсли;

Web-сервис и пакет XDTO для строгой схемы

Web-сервис принимает объект как XML по заранее описанной схеме. Платформа проверит структуру сообщения до того, как управление попадёт в ваш код.

Порядок:

  1. Общие → XDTO-пакеты — создайте пакет со своим пространством имён, например http://example.ru/orders. Опишите тип объекта Order со свойствами id, date, inn, sum и вложенным списком строк.
  2. Общие → Web-сервисы — добавьте сервис, задайте пространство имён URI и в свойстве «Пакеты XDTO» выберите созданный пакет.
  3. Добавьте операцию SaveOrder, параметр order с типом Order, тип возвращаемого значения — string или свой тип ответа.
  4. Опубликуйте базу с флагом публикации Web-сервисов. Описание будет по адресу https://сервер/имя_публикации/ws/имя_сервиса?wsdl.

В обработчике операции параметр приходит как ОбъектXDTO. К свойствам обращаются через точку: order.inn, а повторяющиеся строки — коллекция, которую обходят циклом.

Клиент на 1С вызывает сервис через WSОпределения и WSПрокси. Внешние разработчики генерируют клиентский код по WSDL своими средствами.

После изменения XDTO-пакета меняется WSDL. Клиенты, которые сгенерировали код по старой схеме, начнут получать ошибки разбора. Меняйте схему версиями: новое пространство имён или новая операция.

Проверка данных и обработка ошибок на сервере

Данные с клиента считайте недоверенными. Даже если клиент — ваша же форма.

  • ✅ Обязательные поля. До записи вызовите ДокОбъект.ПроверитьЗаполнение(). Метод вернёт Ложь, если не заполнены реквизиты с проверкой заполнения, а тексты замечаний попадут в сообщения пользователю.
  • 🔎 Поиск по ключам. ИНН, код или GUID из запроса ищите запросом к базе. Не нашли — возвращайте ошибку, а не создавайте пустой элемент справочника.
  • 🔢 Типы и диапазоны. Число из JSON может прийти строкой. Приводите явно и проверяйте, что сумма не отрицательная.
  • 🧾 Транзакция. Если запрос создаёт несколько объектов, оборачивайте запись в НачатьТранзакцию() / ЗафиксироватьТранзакцию() с ОтменитьТранзакцию() в исключении.

Функция записи с разбором замечаний:

Функция ЗаписатьЗаказ(ДокОбъект)
	Если Не ДокОбъект.ПроверитьЗаполнение() Тогда
		Тексты = Новый Массив;
		Для Каждого Сообщение Из ПолучитьСообщенияПользователю(Истина) Цикл
			Тексты.Добавить(Сообщение.Текст);
		КонецЦикла;
		Возврат ОтветJSON(422, СтрСоединить(Тексты, "; "));
	КонецЕсли;
	Попытка
		ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
	Исключение
		Инфо = ИнформацияОбОшибке();
		ЗаписьЖурналаРегистрации("Обмен.ПриёмЗаказа", УровеньЖурналаРегистрации.Ошибка, ,
			ДокОбъект.Ссылка, ПодробноеПредставлениеОшибки(Инфо));
		Возврат ОтветJSON(500, КраткоеПредставлениеОшибки(Инфо));
	КонецПопытки;
	Возврат ОтветJSON(200, Строка(ДокОбъект.Ссылка.УникальныйИдентификатор()));
КонецФункции

Подробности ошибки — в журнал регистрации, клиенту — короткий текст. Так вы не раскрываете наружу имена модулей и строки кода.

Диагностика: выберите симптом

Защита канала и аутентификация

Сервис, который пишет в базу, — дверь в учёт. Настройте её сразу, а не после запуска.

  1. Только HTTPS. Пароль в Basic-аутентификации передаётся в заголовке почти открытым текстом. Без TLS его перехватит любой, кто видит трафик. Сертификат ставят на веб-сервер (IIS или Apache), 1С тут ничего не настраивает.
  2. Отдельный пользователь под обмен. Заведите в базе пользователя, например Обмен, с ролью, где есть права ровно на нужные объекты: чтение справочников-ключей, добавление и проведение заказов. Интерактивный вход ему не нужен.
  3. Не используйте ПривилегированныйРежим без нужды. Если обработчик включает его ради удобства, права пользователя обмена теряют смысл.
  4. Не храните пароль в коде. На стороне 1С-клиента храните его в безопасном хранилище БСП или в константе с ограниченным доступом, а не в тексте модуля.
  5. Ограничьте доступ по сети. Если клиент один и с постоянным IP, разрешите обращения к адресу публикации только с него — средствами веб-сервера или межсетевого экрана.

Не публикуйте HTTP-сервисы базы в интернет под пользователем с полными правами. Одна утечка пароля — и посторонний может менять и проводить документы.

Для разовой отладки удобно временно опубликовать сервис только в локальной сети. Внешний доступ открывайте после того, как отработали проверки и логирование.

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

Можно ли вернуть с сервера на клиент ДокументОбъект?
Нет. На тонком клиенте этого типа нет. Возвращайте ссылку, структуру с полями или помещайте объект в реквизит формы через ЗначениеВРеквизитФормы().
Почему ТаблицаЗначений не передаётся на клиент?
Это серверный тип. Для формы используйте реквизит типа «Таблица значений» (на клиенте он станет коллекцией данных формы) или массив структур.
Чем HTTP-сервис отличается от стандартного интерфейса OData?
OData даёт готовый REST-доступ к объектам без кода, но без вашей логики проверок. HTTP-сервис пишете сами: любой формат, любые проверки, один вызов на бизнес-операцию.
Нужна ли отдельная лицензия для обращений к HTTP-сервису?
Каждое обращение к опубликованному сервису выполняется в сеансе информационной базы и требует клиентской лицензии на время сеанса. Учитывайте это при частых вызовах и считайте лицензии с запасом.
Как передать файл вместе с объектом через HTTP?
Небольшой файл можно вложить в JSON строкой Base64 (Base64Строка() и Base64Значение()). Большой лучше отправить отдельным запросом с двоичным телом и связать с объектом по GUID.