Web-сервис 1С — объект конфигурации, который принимает SOAP-запросы и отвечает по контракту из WSDL-описания: внешняя система видит операции и типы, а 1С выполняет функцию модуля сервиса и возвращает типизированный XML. Ниже — полный пример: XDTO-пакет, сервис с тремя операциями, модуль, права, публикация, проверка в SoapUI и вызов из другой базы.
Запросы в примере читают справочник Номенклатура и регистр ТоварыНаСкладах — имена сверены по выгрузкам УТ 11.4 и КА 2.5.
SOAP выбирают, когда другая сторона работает по WSDL-контракту: интеграционная шина, WMS на Java или .NET, система банка. Клиент генерирует классы по WSDL и получает строгие типы, а 1С в этой схеме — SOAP-сервер.
Второй сценарий — обмен между базами 1С. Синхронизация данных БСП через интернет вызывает web-сервисы второй базы: в УТ 11.4 это Exchange_3_0_1_1 и предыдущие версии с операциями Upload, Download, TestConnection. Свой сервис пишут, когда типового обмена нет: например, магазин при продаже запрашивает остатки центральной базы. Чтобы передавать только изменения, сервис сочетают с планом обмена. Сайту и мобильному приложению удобнее REST и JSON — для них есть HTTP-сервис.
Сложные параметры и ответ описывают типами XDTO-пакета. В примере это пакет StockTypes с пространством имён http://example.ru/stock/types:
| Тип объекта | Свойства | Назначение |
|---|---|---|
ArticleList | Article — xs:string, границы 0..-1 | входной список артикулов |
StockItem | Article, Name — xs:string; Quantity — xs:decimal; Found — xs:boolean | остаток по артикулу |
StockList | Date — xs:dateTime; Item — StockItem, границы 0..-1 | ответ GetStock |
Пакет создают в ветке Общие → XDTO-пакеты вручную или импортом XSD: команда «Импорт XML-схемы…» в контекстном меню ветки создаст пакет из схемы ниже, останется задать имя.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.ru/stock/types"
targetNamespace="http://example.ru/stock/types"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:complexType name="ArticleList">
<xs:sequence>
<xs:element name="Article" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="StockItem">
<xs:sequence>
<xs:element name="Article" type="xs:string"/>
<xs:element name="Name" type="xs:string"/>
<xs:element name="Quantity" type="xs:decimal"/>
<xs:element name="Found" type="xs:boolean"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="StockList">
<xs:sequence>
<xs:element name="Date" type="xs:dateTime"/>
<xs:element name="Item" type="tns:StockItem" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Имена типов — латиницей: из них генераторы клиентов на Java или C# сделают классы. Пространство имён пакета отделено от пространства имён сервиса, как в типовых: в УТ 11.4 сервис EquipmentService объявлен в http://www.1c.ru/EquipmentService, а один из его пакетов — в http://www.1c.ru/EquipmentService/1.0.0.6. Подробнее о пакетах — в статье XDTO в 1С.
StockService.http://example.ru/stock, «Пакеты XDTO» — StockTypes, «Имя файла публикации» — stock.1cws.| Операция | Имя процедуры | Параметры | Возвращает |
|---|---|---|---|
Ping | Пинг | нет | xs:string |
GetStock | ПолучитьОстатки | Articles — ArticleList, входной; Warehouse — xs:string, входной, возможно пустое | StockList |
FindItem | НайтиТовар | Article — xs:string, входной; Name, Unit — xs:string, выходные | xs:boolean |
Имя операции видит клиент, имя процедуры — только разработчик, поэтому она может быть русской. Параметры функции сопоставляются с параметрами операции по порядку: в БСП операцию Upload с параметром ExchangePlanName обрабатывает ВыполнитьВыгрузку(ИмяПланаОбмена, …).
| Тип в операции | Значение в модуле |
|---|---|
| xs:string | Строка |
| xs:decimal, xs:int | Число |
| xs:boolean | Булево |
| xs:dateTime, xs:date | Дата |
| xs:base64Binary | ДвоичныеДанные |
| тип объекта из пакета | ОбъектXDTO |
| свойство с верхней границей -1 | СписокXDTO |
| xsi:nil при «Возможно пустое значение» | Неопределено |
Если обе стороны — 1С, можно подключить пакет http://v8.1c.ru/8.1/data/core и передавать платформенные типы: в БСП выходной параметр Data операции Upload имеет тип ValueStorage, и сервис присваивает ему ХранилищеЗначения. Сторонней системе такие типы не подходят.
Модуль открывается ссылкой «Модуль» в палитре свойств сервиса. Ниже он целиком.
// Модуль web-сервиса StockService. Выполняется только на сервере,
// директивы компиляции в нем не пишут.
// Пространство имен XDTO-пакета StockTypes
Функция URIТипов()
Возврат "http://example.ru/stock/types";
КонецФункции
// Пустой объект XDTO заданного типа из пакета StockTypes
Функция НовыйОбъектXDTO(ИмяТипа)
ТипОбъекта = ФабрикаXDTO.Тип(URIТипов(), ИмяТипа);
Если ТипОбъекта = Неопределено Тогда
ВызватьИсключение СтрШаблон("Тип XDTO {%1}%2 не найден", URIТипов(), ИмяТипа);
КонецЕсли;
Возврат ФабрикаXDTO.Создать(ТипОбъекта);
КонецФункции
// Операция Ping: проверка публикации, авторизации и прав
Функция Пинг()
Возврат СтрШаблон("StockService OK. Пользователь: %1, время сервера: %2",
ИмяПользователя(), XMLСтрока(ТекущаяДатаСеанса()));
КонецФункции
// Операция GetStock.
// Артикулы - ОбъектXDTO типа ArticleList;
// ИмяСклада - Строка или Неопределено, если клиент передал xsi:nil.
// Возвращает ОбъектXDTO типа StockList.
Функция ПолучитьОстатки(Артикулы, ИмяСклада)
Попытка
Возврат ОстаткиПоАртикулам(Артикулы, ИмяСклада);
Исключение
// Клиент получит SOAP Fault с текстом ошибки, стек остается в журнале
ЗаписьЖурналаРегистрации("StockService.GetStock", УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение;
КонецПопытки;
КонецФункции
Функция ОстаткиПоАртикулам(Артикулы, ИмяСклада)
// Список артикулов без пустых строк и дублей
СписокАртикулов = Новый Массив;
Если Артикулы <> Неопределено Тогда
Для Каждого ЗначениеАртикула Из Артикулы.Article Цикл
Артикул = СокрЛП(ЗначениеАртикула);
Если ЗначениеЗаполнено(Артикул) И СписокАртикулов.Найти(Артикул) = Неопределено Тогда
СписокАртикулов.Добавить(Артикул);
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если СписокАртикулов.Количество() = 0 Тогда
ВызватьИсключение "Не передан ни один артикул";
ИначеЕсли СписокАртикулов.Количество() > 500 Тогда
ВызватьИсключение "За один вызов можно запросить не больше 500 артикулов";
КонецЕсли;
// Пустой Warehouse - остатки по всем складам
Склад = Справочники.Склады.ПустаяСсылка();
Если ЗначениеЗаполнено(ИмяСклада) Тогда
Склад = Справочники.Склады.НайтиПоНаименованию(СокрЛП(ИмяСклада), Истина);
Если Склад.Пустая() Тогда
ВызватьИсключение СтрШаблон("Склад ""%1"" не найден", ИмяСклада);
КонецЕсли;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Артикул КАК Артикул,
| Товары.Наименование КАК Наименование,
| ЕСТЬNULL(СУММА(Остатки.ВНаличииОстаток), 0) КАК Количество
|ИЗ
| Справочник.Номенклатура КАК Товары
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(
| ,
| Номенклатура.Артикул В (&Артикулы)
| И (&ВсеСклады = ИСТИНА
| ИЛИ Склад = &Склад)) КАК Остатки
| ПО Товары.Ссылка = Остатки.Номенклатура
|ГДЕ
| Товары.Артикул В (&Артикулы)
| И НЕ Товары.ЭтоГруппа
| И НЕ Товары.ПометкаУдаления
|
|СГРУППИРОВАТЬ ПО
| Товары.Ссылка,
| Товары.Артикул,
| Товары.Наименование";
Запрос.УстановитьПараметр("Артикулы", СписокАртикулов);
Запрос.УстановитьПараметр("ВсеСклады", Склад.Пустая());
Запрос.УстановитьПараметр("Склад", Склад);
Ответ = НовыйОбъектXDTO("StockList");
Ответ.Date = ТекущаяДатаСеанса();
Найденные = Новый Соответствие;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Ответ.Item.Добавить(ПозицияОстатка(Выборка.Артикул, Выборка.Наименование, Выборка.Количество, Истина));
Найденные.Вставить(ВРег(Выборка.Артикул), Истина);
КонецЦикла;
// Артикулы, которых нет в базе, возвращаем с Found = false
Для Каждого Артикул Из СписокАртикулов Цикл
Если Найденные[ВРег(Артикул)] = Неопределено Тогда
Ответ.Item.Добавить(ПозицияОстатка(Артикул, "", 0, Ложь));
КонецЕсли;
КонецЦикла;
Возврат Ответ;
КонецФункции
// Объект XDTO типа StockItem
Функция ПозицияОстатка(Артикул, Наименование, Количество, Найден)
Позиция = НовыйОбъектXDTO("StockItem");
Позиция.Article = Артикул;
Позиция.Name = Наименование;
Позиция.Quantity = Количество;
Позиция.Found = Найден;
Возврат Позиция;
КонецФункции
// Операция FindItem. Артикул - входной параметр,
// Наименование и ЕдиницаИзмерения - выходные: им достаточно присвоить значения.
Функция НайтиТовар(Артикул, Наименование, ЕдиницаИзмерения)
Наименование = "";
ЕдиницаИзмерения = "";
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Товары.Наименование КАК Наименование,
| ПРЕДСТАВЛЕНИЕ(Товары.ЕдиницаИзмерения) КАК ЕдиницаИзмерения
|ИЗ
| Справочник.Номенклатура КАК Товары
|ГДЕ
| Товары.Артикул = &Артикул
| И НЕ Товары.ЭтоГруппа
| И НЕ Товары.ПометкаУдаления";
Запрос.УстановитьПараметр("Артикул", СокрЛП(Артикул));
Выборка = Запрос.Выполнить().Выбрать();
Если Не Выборка.Следующий() Тогда
Возврат Ложь;
КонецЕсли;
Наименование = Выборка.Наименование;
ЕдиницаИзмерения = Выборка.ЕдиницаИзмерения;
Возврат Истина;
КонецФункции
ФабрикаXDTO.Тип() при опечатке в URI или имени возвращает Неопределено — НовыйОбъектXDTO проверяет это сразу, а не на Создать.Артикулы.Article — СписокXDTO: обход Для Каждого отдаёт значения элементов, для xs:string — строки. Пустые и повторные артикулы отбрасываются, больше 500 за вызов не принимаются.ВызватьИсключение в обработчике превращается в SOAP Fault с текстом ошибки. ПолучитьОстатки сначала пишет подробности в журнал регистрации, затем пробрасывает исключение оператором ВызватьИсключение;.Склады в УТ 11.4 и КА 2.5 нет кода. В боевой интеграции надёжнее GUID.Found = false — клиент отличит «нет товара» от «нет остатка».НайтиТовар достаточно присвоить значения — платформа добавит их в ответ.Запрос из ОстаткиПоАртикулам удобно отладить в консоли запросов.
Операция выполняется от имени пользователя информационной базы, права проверяет платформа:
ИспользованиеСервисаОстатков: «Использование» на операции Ping, GetStock, FindItem и «Чтение» справочников Номенклатура, Склады и регистра ТоварыНаСкладах;ws_partner с аутентификацией 1С:Предприятия. В конфигурациях на БСП роль включают в профиль групп доступа.Веб-сервер и модули расширения веб-сервера 1С ставятся так же, как для HTTP-сервиса. Дальше:
trade.StockService.Фрагмент default.vrd:
<?xml version="1.0" encoding="UTF-8"?>
<point xmlns="http://v8.1c.ru/8.2/virtual-resource-system"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
base="/trade"
ib="Srvr="srv01";Ref="trade";">
<ws pointEnableCommon="false"
publishExtensionsByDefault="false">
<point name="StockService"
alias="stock.1cws"
enable="true"
reuseSessions="autouse"
sessionMaxAge="20"
poolSize="10"
poolTimeout="5"/>
</ws>
</point>
При pointEnableCommon="false" работают только сервисы из point с enable="true"; publishExtensionsByDefault отвечает за сервисы расширений. reuseSessions="autouse" включает пул сеансов, и новый сеанс не открывается на каждый вызов. Поэтому состояние между вызовами в параметрах сеанса не храните.
Описание открывается по адресу http://srv01/trade/ws/stock.1cws?wsdl или по имени сервиса — /ws/StockService?wsdl, так адрес строит БСП. В WSDL — схемы типов, сообщения, привязки SOAP 1.1 и 1.2 с точками подключения StockServiceSoap и StockServiceSoap12 и адрес вызова. Это контракт для партнёра. Адрес вызова платформа берёт из адреса запроса: WSDL, открытый на сервере через localhost, будет содержать localhost.
Ping.ws_partner.GetStock замените «?» значениями.<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:st="http://example.ru/stock"
xmlns:typ="http://example.ru/stock/types">
<soapenv:Header/>
<soapenv:Body>
<st:GetStock>
<st:Articles>
<typ:Article>SKU-001</typ:Article>
<typ:Article>SKU-404</typ:Article>
</st:Articles>
<st:Warehouse>Основной склад</st:Warehouse>
</st:GetStock>
</soapenv:Body>
</soapenv:Envelope>
Префиксы SoapUI назначит свои. Для всех складов передайте пустой Warehouse или xsi:nil="true". Ответ сокращённо:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header/>
<soap:Body>
<m:GetStockResponse xmlns:m="http://example.ru/stock">
<m:return xmlns:t="http://example.ru/stock/types">
<t:Date>2026-10-05T11:20:00</t:Date>
<t:Item>
<t:Article>SKU-001</t:Article>
<t:Name>Кабель USB-C 1 м</t:Name>
<t:Quantity>48</t:Quantity>
<t:Found>true</t:Found>
</t:Item>
<t:Item>
<t:Article>SKU-404</t:Article>
<t:Name/>
<t:Quantity>0</t:Quantity>
<t:Found>false</t:Found>
</t:Item>
</m:return>
</m:GetStockResponse>
</soap:Body>
</soap:Envelope>
Исключение в обработчике приходит ответом 500 с soap:Fault, текст ошибки — в faultstring.
Другая база вызывает сервис через WSОпределения и WSПрокси. В тонком клиенте их нет, поэтому код размещают в серверном общем модуле или модуле объекта.
// Вызов web-сервиса StockService из другой базы 1С.
// Код серверный: WSОпределения и WSПрокси на тонком клиенте недоступны.
// Прокси сервиса остатков.
// Подключение - структура с полями АдресWSDL, Пользователь, Пароль.
Функция ПроксиСервисаОстатков(Подключение)
ЗащищенноеСоединение = Неопределено;
Если СтрНачинаетсяС(НРег(Подключение.АдресWSDL), "https://") Тогда
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL;
КонецЕсли;
Определения = Новый WSОпределения(Подключение.АдресWSDL, Подключение.Пользователь,
Подключение.Пароль, , 30, ЗащищенноеСоединение);
Прокси = Новый WSПрокси(Определения, "http://example.ru/stock", "StockService",
"StockServiceSoap", , 60, ЗащищенноеСоединение);
Прокси.Пользователь = Подключение.Пользователь;
Прокси.Пароль = Подключение.Пароль;
Возврат Прокси;
КонецФункции
// Остатки по массиву артикулов из учетной базы.
// Возвращает таблицу значений с колонками Артикул, Наименование, Количество, Найден.
Функция ОстаткиИзУчетнойБазы(Подключение, МассивАртикулов, ИмяСклада = Неопределено) Экспорт
Прокси = ПроксиСервисаОстатков(Подключение);
Фабрика = Прокси.ФабрикаXDTO; // типы из WSDL сервиса
// Параметр Articles: объект ArticleList, элементы списка - значения xs:string
Артикулы = Фабрика.Создать(Фабрика.Тип("http://example.ru/stock/types", "ArticleList"));
ТипСтрока = Фабрика.Тип("http://www.w3.org/2001/XMLSchema", "string");
Для Каждого Артикул Из МассивАртикулов Цикл
Артикулы.Article.Добавить(Фабрика.Создать(ТипСтрока, Артикул));
КонецЦикла;
Попытка
Ответ = Прокси.GetStock(Артикулы, ИмяСклада); // Неопределено уйдет как xsi:nil
Исключение
ЗаписьЖурналаРегистрации("Интеграция.СервисОстатков", УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Ошибка вызова сервиса остатков: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
Результат = Новый ТаблицаЗначений;
Результат.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка"));
Результат.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));
Результат.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
Результат.Колонки.Добавить("Найден", Новый ОписаниеТипов("Булево"));
Для Каждого Позиция Из Ответ.Item Цикл
СтрокаТаблицы = Результат.Добавить();
СтрокаТаблицы.Артикул = Позиция.Article;
СтрокаТаблицы.Наименование = Позиция.Name;
СтрокаТаблицы.Количество = Позиция.Quantity;
СтрокаТаблицы.Найден = Позиция.Found;
КонецЦикла;
Возврат Результат;
КонецФункции
// Операция с выходными параметрами: Наименование и Единицу заполнит сервис
Функция ОписаниеТовара(Подключение, Артикул) Экспорт
Прокси = ПроксиСервисаОстатков(Подключение);
Наименование = "";
Единица = "";
Если Прокси.FindItem(Артикул, Наименование, Единица) Тогда
Возврат СтрШаблон("%1, ед.: %2", Наименование, Единица);
КонецЕсли;
Возврат "";
КонецФункции
WSПрокси указывают пространство имён сервиса, а не пакета; точка подключения — имя сервиса плюс Soap.Прокси.ФабрикаXDTO: объект ArticleList создаёт она, в список кладутся значения XDTO.TestConnection.Попытка.В конфигурации на БСП прокси удобнее получать типовой функцией: она кэширует WSDL (в УТ 11.4 — на сутки), берёт настройки прокси-сервера из программы, а при ДелатьКонтрольныйВызов и таймауте больше 20 секунд сначала вызывает операцию Ping.
// Тот же прокси средствами БСП: WSDL кэшируется в регистре сведений
// КэшПрограммныхИнтерфейсов, настройки прокси-сервера берутся из программы.
// Пароль заранее записан в безопасное хранилище:
// ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище("Интеграция.СервисОстатков", Пароль)
Функция ПроксиСервисаОстатковБСП(АдресWSDL, Пользователь) Экспорт
УстановитьПривилегированныйРежим(Истина);
Пароль = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища("Интеграция.СервисОстатков");
УстановитьПривилегированныйРежим(Ложь);
ПараметрыПрокси = ОбщегоНазначения.ПараметрыПодключенияWSПрокси();
ПараметрыПрокси.АдресWSDL = АдресWSDL;
ПараметрыПрокси.URIПространстваИмен = "http://example.ru/stock";
ПараметрыПрокси.ИмяСервиса = "StockService"; // точка подключения по умолчанию - StockServiceSoap
ПараметрыПрокси.ИмяПользователя = Пользователь;
ПараметрыПрокси.Пароль = Пароль;
ПараметрыПрокси.Таймаут = 60;
ПараметрыПрокси.ДелатьКонтрольныйВызов = Истина; // сначала вызовет операцию Ping
Возврат ОбщегоНазначения.СоздатьWSПрокси(ПараметрыПрокси);
КонецФункции
Пароль держат не в коде, а в безопасном хранилище — туда его записывает ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище.
| Ошибка | Причина | Что сделать |
|---|---|---|
404 на адресе ?wsdl | Сервис не отмечен при публикации, опечатка в имени файла публикации | Сверить point в default.vrd, перезапустить веб-сервер |
| 401 Unauthorized | Не задана авторизация Basic, неверный пароль, выключена аутентификация 1С:Предприятия | Проверить логин в браузере |
| SOAP Fault «Нарушение прав доступа!» | Нет права «Использование» на операцию или «Чтение» на данные; в типовой с ограничением на уровне записей служебному пользователю открыты не все склады | Дописать права в роль, открыть склады группе доступа |
| SOAP Fault с ошибкой преобразования или проверки данных XDTO | Элемент не в том пространстве имён, текст в поле xs:decimal, нет обязательного элемента | Взять шаблон запроса из актуального WSDL |
| Клиент обращается на localhost | WSDL получен по внутреннему адресу | Открывать WSDL по внешнему адресу или передать «Местоположение» в конструктор WSПрокси |
| Новая операция не видна клиенту | Старый WSDL в проекте SoapUI или в кэше БСП | Update Definition в SoapUI, в 1С — заново получить WSОпределения |
| «Тип не определен (WSОпределения)» | Вызов в клиентской процедуре | Перенести код на сервер |
| Каждый вызов медленный | Без повторного использования сеансов на вызов открывается новый сеанс | reuseSessions="autouse" |
Web-сервис — это SOAP: XML-конверт, WSDL-контракт, типы из XDTO-пакетов, разбор запроса берёт на себя платформа. HTTP-сервис — свободный REST: адреса, методы и формат задаёт разработчик, разбор пишется в коде. SOAP берут, когда его требует другая сторона.
Да, собственный XDTO-пакет и web-сервис создаются в расширении конфигурации. При публикации включите публикацию web-сервисов расширений (publishExtensionsByDefault).
Любым SOAP-клиентом, который строит вызовы по WSDL: в Python — например, библиотекой zeep, в PHP — встроенным SoapClient. Нужны адрес WSDL и Basic-авторизация служебного пользователя, имена операций и параметров — из WSDL.
Да. WS-ссылка (Общие → WS-ссылки → Добавить, в окне указывают адрес WSDL) хранит описание в конфигурации: WSСсылки.СервисОстатков.СоздатьWSПрокси("http://example.ru/stock", "StockService", "StockServiceSoap"). После изменения сервиса ссылку придётся обновить в конфигураторе.
Если сервис нужен под конкретного партнёра — с согласованным WSDL, тестовым контуром и записью данных в документы, — быстрее поручить его исполнителю: доработка и интеграция 1С. Опишите конфигурацию, внешнюю систему и операции в форме задания: оценка бесплатная, ответ в течение рабочего дня.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.