Как отправить XML на внешний веб-сервис из 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Интеграция учетных систем с внешними сервисами — одна из классических задач разработчика 1С. Нередко возникает ситуация, когда при наступлении определенного события необходимо собрать данные и передать их на сторонний веб-сервис в формате XML. При этом сохранять промежуточный файл на диск не требуется. Разберем подробно, какими инструментами платформы 1С:Предприятие 8 можно решить эту задачу, как правильно обращаться к удаленным методам и избежать типичных ошибок при работе с объектами WSПрокси и фабрикой XDTO.

Способ 1. Штатная работа через WSОпределения и WSПрокси

Основной и наиболее правильный способ взаимодействия с SOAP веб-сервисами в 1С — это использование встроенных механизмов WS. При таком подходе платформа сама считывает WSDL-описание сервиса и формирует типизированные прокси-объекты.

Рассмотрим по шагам реализацию данного механизма:

  1. Получение WSDL-определения сервиса. Для этого создается объект WSОпределения, куда передается ссылка на WSDL, а также логин и пароль при наличии авторизации. Если сервис работает по протоколу HTTPS, дополнительно настраивается защищенное соединение через ЗащищенноеСоединениеOpenSSL.
  2. Инициализация прокси. На базе определений создается объект WSПрокси, в который передаются URI пространства имен, имя сервиса и имя точки подключения (порта).
  3. Создание и передача параметров. Если веб-сервис принимает сложные типы данных (объекты XDTO), они инициализируются с помощью фабрики XDTO сервиса.

Посмотрим на практический пример вызова веб-сервиса с заполнением типизированных параметров:


// Настраиваем защищенное соединение при работе по HTTPS
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL(
    Новый СертификатКлиентаWindows(), 
    Новый СертификатыУдостоверяющихЦентровWindows()
);

ИмяВебСервиса = "https://example.com/ws/service.asmx?WSDL";
Пользователь  = "login";
Пароль        = "password";

// Считываем описание сервиса
WS_Определения = Новый WSОпределения(ИмяВебСервиса, Пользователь, Пароль,,, ЗащищенноеСоединение);

// Получаем метаданные сервиса
СервисДанные   = WS_Определения.Сервисы[0];
Пространство   = СервисДанные.URIПространстваИмен;
ИмяСервиса     = СервисДанные.Имя;
ТочкаВхода     = СервисДанные.ТочкиПодключения[0].Имя;

// Создаем прокси
Прокси = Новый WSПрокси(WS_Определения, Пространство, ИмяСервиса, ТочкаВхода,, ЗащищенноеСоединение);
Прокси.Пользователь = Пользователь;
Прокси.Пароль       = Пароль;
Прокси.Таймаут      = 60; // Указываем таймаут в секундах, чтобы избежать зависания

// Создаем структуру запроса через Фабрику XDTO веб-сервиса
ТипПараметра = Прокси.ФабрикаXDTO.Тип(Пространство, "RequestData");
WSПараметр   = Прокси.ФабрикаXDTO.Создать(ТипПараметра);

WSПараметр.Address = "г. Москва";
WSПараметр.Phone   = "+79990000000";

// Вызываем метод веб-сервиса
Результат = Прокси.SendData(WSПараметр);

Причина ошибки «Поле объекта не обнаружено» при вызове метода WSПрокси

Часто разработчики сталкиваются с ситуацией, когда код Прокси.ИмяМетода(Параметры) завершается аварийно с ошибкой «Поле объекта не обнаружено». Выясним причину этой проблемы. Она кроется в одной из следующих деталей:

  1. Неправильно выбрана точка подключения (порт). В одном WSDL-файле сервис может объявлять несколько точек подключения (например, отдельные endpoints для SOAP 1.1, SOAP 1.2 или HTTP GET/POST). Если в коде без разбора берется первая попавшаяся точка СервисДанные.ТочкиПодключения[0].Имя, платформа может выбрать порт, не поддерживающий требуемую операцию. Необходимо явно указывать имя SOAP-порта (например, ServiceNameSoap).
  2. Регистр букв и несовпадение имени. Платформа 1С чувствительна к точному совпадению наименования операции. Имя вызываемого метода должно строго повторять атрибут name у тега wsdl:operation в схеме, а не имя входящего XDTO-сообщения или сложного типа данных.
  3. Стиль WSDL. Платформа 1С корректно работает со стилем Document/literal. Если сторонний сервис описан в устаревшем стиле RPC/encoded, платформа не сможет динамически сгенерировать исполняемые методы у объекта WSПрокси.

Способ 2. Автоматическая десериализация готовой строки XML в XDTO

Если у вас уже есть готовая XML-строка, сформированная по правилам удаленного сервиса, вовсе не обязательно вручную заполнять каждый реквизит XDTO через цикл. Преобразуем входящую строку напрямую в объект нужного типа с помощью фабрики XDTO:


// Допустим, у нас есть строка с XML-данными
ТекстXML = "<RequestData xmlns=""http://example.com/service"">"
         + "  <Address>г. Москва</Address>"
         + "  <Phone>+79990000000</Phone>"
         + "</RequestData>";

// Читаем XML из памяти
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ТекстXML);

// Получаем целевой тип XDTO из фабрики прокси
ТипОбъекта = Прокси.ФабрикаXDTO.Тип("http://example.com/service", "RequestData");

// Десериализуем строку в полноценный объект XDTO
ОбъектПараметра = Прокси.ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ТипОбъекта);
ЧтениеXML.Закрыть();

// Передаем десериализованный объект в метод сервиса
Результат = Прокси.SendData(ОбъектПараметра);

Способ 3. Формирование XML в оперативной памяти

Чтобы не сохранять XML во временные файлы на жестком диске перед отправкой, задействуем связку объекта ЗаписьXML и оперативной памяти платформы. Метод УстановитьСтроку() позволяет производить запись прямо в переменную:


ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку(); // Инициализация записи в память

ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("RootData");
ЗаписьXML.ЗаписатьАтрибут("Version", "1.0");

ЗаписьXML.ЗаписатьНачалоЭлемента("Item");
ЗаписьXML.ЗаписатьТекст("Значение элемента");
ЗаписьXML.ЗаписатьКонецЭлемента(); // Item

ЗаписьXML.ЗаписатьКонецЭлемента(); // RootData

// Получаем готовую XML-строку
ИтоговыйXML = ЗаписьXML.Закрыть();

Способ 4. Прямая отправка SOAP-конверта через HTTPСоединение

В некоторых случаях обращение через WSПрокси бывает невозможным: сервис требует специфические заголовки, цифровую подпись сообщения WS-Security (WSS) или использует нестандартные типы данных. В такой ситуации формируют SOAP-конверт вручную и отправляют его как стандартный HTTP POST-запрос.

Важное замечание: использование внешних COM-объектов Windows (таких как MSXML2.xmlHttp или WinHttp.WinHttpRequest) делает код неработоспособным на серверах под управлением Linux. Рекомендуется использовать встроенный кроссплатформенный объект HTTPСоединение.

Разберем пример отправки сырого XML через HTTPСоединение:


// Формируем полный текст SOAP-конверта
ТекстЗапросаSOAP = 
"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:ws=""http://example.com/service"">" +
"   <soapenv:Header/>" +
"   <soapenv:Body>" +
"      <ws:SendData>" +
"         <ws:Address>г. Москва</ws:Address>" +
"         <ws:Phone>+79990000000</ws:Phone>" +
"      </ws:SendData>" +
"   </soapenv:Body>" +
"</soapenv:Envelope>";

Сервер = "example.com";
Порт   = 443;
Путь   = "/ws/service.asmx";

ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();
Соединение = Новый HTTPСоединение(Сервер, Порт, "login", "password",, 60, ЗащищенноеСоединение);

Запрос = Новый HTTPЗапрос(Путь);
// Устанавливаем обязательные заголовки для SOAP 1.1
Запрос.Заголовки.Вставить("Content-Type", "text/xml; charset=utf-8");
Запрос.Заголовки.Вставить("SOAPAction", "http://example.com/service/SendData");

// Записываем тело запроса из строки в UTF-8 без использования BOM
Запрос.УстановитьТелоИзСтроки(ТекстЗапросаSOAP, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);

Попытка
    Ответ = Соединение.ОтправитьДляОбработки(Запрос);
    Если Ответ.КодСостояния = 200 Тогда
        ТекстОтвета = Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
        // Обрабатываем полученный XML-ответ
    Иначе
        ВызватьИсключение "Ошибка сервиса. Код: " + Ответ.КодСостояния;
    КонецЕсли;
Исключение
    Сообщить("Не удалось выполнить запрос к сервису: " + ОписаниеОшибки());
КонецПопытки;

Нюансы и рекомендации

  1. Управление таймаутом. Всегда явно задавайте таймаут у объектов WSПрокси или HTTPСоединение. По умолчанию он равен 0 (бесконечное ожидание), что при проблемах на стороне шлюза приведет к полной блокировке сеанса пользователя или зависанию фонового задания.
  2. Кэширование WSDL. Механизм WSОпределения кэширует схему сервиса на время сеанса 1С. Если разработчики удаленного сервиса обновили состав методов, 1С не увидит изменений до перезапуска сеанса (или перезапуска рабочего процесса сервера 1С).
← На главную