При интеграции 1С с внешними информационными системами часто возникает задача работы с веб-сервисами, которые требуют соблюдения строгой последовательности вызовов. Одной из таких задач является работа с сервисами, построенными на базе фреймворка RemObjects SDK (например, логистический сервис Envialia). Особенность таких систем заключается в том, что авторизация происходит в одном сервисе, а работа с данными — в другом, при этом идентификатор сессии должен передаваться в специальном SOAP-заголовке ROClientIDHeader.
В этой статье мы подробно разберем, как реализовать этот механизм в 1С, проанализируем примеры кода и рассмотрим два основных способа решения проблемы: использование стандартных WS-ссылок с программным добавлением заголовков и формирование прямых HTTP-запросов.
Рассмотрим типичный сценарий: поставщик предоставляет два WSDL-описания:
LoginWSService — для получения идентификатора сессии (GUID).WebServService — для выполнения бизнес-операций (получение данных, создание заявок и т.д.).Проблема заключается в том, что после успешного вызова метода Login, полученный ID сессии необходимо передать во второй сервис. В языке C# это решается простым присваиванием свойства объекту прокси, но в 1С структура WSПрокси не всегда автоматически предоставляет доступ к таким полям заголовков.
Для начала нам необходимо авторизоваться в системе. Предположим, мы уже импортировали WSDL первого сервиса в объект WSСсылка.Envialia_LoginWSService. Рассмотрим код получения сессии:
НаименованиеВебСервиса = "LoginWSService";
НаименованиеПорта = "LoginWSServicePort";
URI_ПространстваИмен = "http://tempuri.org/"; // Обычно используется этот URI
// Создаем прокси для авторизации
ВебСервис = WSСсылки.Envialia_LoginWSService.СоздатьWSПрокси(URI_ПространстваИмен, НаименованиеВебСервиса, НаименованиеПорта);
// Вызываем метод логина. Параметры зависят от конкретной реализации сервиса.
// В примере ниже используется метод LoginCli2
РезультатЛогина = ВебСервис.LoginCli2(КодАгента, Клиент, Пароль, Результат, КодВыхода, Код, Имя, КодCR, Тип, Версия, Ошибка, Сессия, URL);
// Идентификатор сессии обычно возвращается в формате GUID, например: {C5C720BF-94B9-4F64-A93C-F1E14FD5E9E4}
ID_Сессии = Сессия;
Теперь, когда у нас есть ID_Сессии, наша задача — передать его во второй сервис WebServService.
Этот метод является наиболее правильным с точки зрения архитектуры 1С, так как мы продолжаем использовать типизированные объекты и фабрику XDTO. Нам нужно вручную внедрить SOAP-заголовок в запрос.
Шаг 1.1. Изучение структуры XDTO. Откройте вашу WS-ссылку в конфигураторе. В ветке "Типы объектов" найдите определение ROClientIDHeader. Нам нужно точно знать его имя и пространство имен (Namespace URI).
Шаг 1.2. Программное создание заголовка. Разберем по шагам процесс формирования и вставки заголовка:
// 1. Создаем прокси для основного сервиса работы с данными
ПроксиДанных = WSСсылки.Envialia_WebServService.СоздатьWSПрокси("http://tempuri.org/", "WebServService", "WebServServicePort");
// 2. Получаем тип заголовка из фабрики XDTO, связанной с этой ссылкой
ТипЗаголовка = WSСсылки.Envialia_WebServService.ФабрикаXDTO.Тип("http://tempuri.org/", "ROClientIDHeader");
// 3. Создаем объект заголовка
ОбъектЗаголовка = WSСсылки.Envialia_WebServService.ФабрикаXDTO.Создать(ТипЗаголовка);
ОбъектЗаголовка.ID = ID_Сессии; // Передаем полученный ранее GUID
// 4. Оборачиваем объект XDTO в специальный параметр заголовка 1С
ПараметрЗаголовка = Новый WSПараметрЗаголовка("ROClientIDHeader", ОбъектЗаголовка, "http://tempuri.org/", Ложь);
// 5. Вставляем заголовок в прокси. Теперь каждый вызов через этот прокси будет содержать ID сессии
ПроксиДанных.ВставитьЗаголовок(ПараметрЗаголовка);
// 6. Вызываем целевой метод сервиса
РезультатЗапроса = ПроксиДанных.ConsEnvEstados("параметр1", "параметр2", "параметр3");
Важно помнить: метод ВставитьЗаголовок добавляет заголовок для всех последующих вызовов в рамках данного объекта WSПрокси. Если вы пересоздаете прокси, заголовок нужно вставлять заново.
Иногда WSDL-описание сервиса настолько сложное или специфичное, что стандартный импорт в 1С работает некорректно. В таких случаях мы можем самостоятельно сформировать XML (SOAP-пакет) и отправить его методом POST.
Проанализируем структуру SOAP-пакета, который нам нужно собрать:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header>
<tem:ROClientIDHeader>
<tem:ID>{C5C720BF-94B9-4F64-A93C-F1E14FD5E9E4}</tem:ID>
</tem:ROClientIDHeader>
</soapenv:Header>
<soapenv:Body>
<tem:ConsEnvEstados>
<tem:strAgencia>agencia-cargo</tem:strAgencia>
<tem:strOrigen>agencia-origen</tem:strOrigen>
<tem:strAlbaran>albaran</tem:strAlbaran>
</tem:ConsEnvEstados>
</soapenv:Body>
</soapenv:Envelope>
Теперь реализуем отправку этого пакета в 1С:
// Формируем тело запроса (рекомендуется использовать ЗаписьXML)
ТекстЗапроса =
"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:tem=""http://tempuri.org/"">" +
"<soapenv:Header><tem:ROClientIDHeader><tem:ID>" + ID_Сессии + "</tem:ID></tem:ROClientIDHeader></soapenv:Header>" +
"<soapenv:Body><tem:ConsEnvEstados>...параметры...</tem:ConsEnvEstados></soapenv:Body></soapenv:Envelope>";
// Настраиваем соединение
Соединение = Новый HTTPСоединение("сервер.com", 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());
// Устанавливаем заголовки HTTP
Заголовки = Новый Соответствие();
Заголовки.Вставить("Content-Type", "text/xml; charset=utf-8");
Заголовки.Вставить("SOAPAction", "http://tempuri.org/IWebServService/ConsEnvEstados");
// Отправляем запрос
ЗапросHTTP = Новый HTTPЗапрос("/soap/IWebServService", Заголовки);
ЗапросHTTP.УстановитьТелоИзСтроки(ТекстЗапроса, КодировкаТекста.UTF8);
Ответ = Соединение.ОтправитьДляОбъекта(ЗапросHTTP);
Если Ответ.КодСостояния = 200 Тогда
// Обрабатываем полученный XML через ЧтениеXML
ТекстОтвета = Ответ.ПолучитьТелоКакСтроку();
Иначе
Сообщить("Ошибка вызова: " + Ответ.КодСостояния);
КонецЕсли;
Рассмотрим несколько критических моментов, которые часто становятся причиной ошибок при интеграции:
{...}, а некоторые — без них. Проверьте документацию поставщика. Если сессия возвращается со скобками, попробуйте передать их именно так."Неизвестный заголовок" часто возникает из-за неверного URI пространства имен. В RemObjects часто используется http://tempuri.org/, но оно может отличаться. Проверьте атрибут xmlns в исходном WSDL файле.Login, обновить ID сессии и повторить исходный запрос.HTTPСоединение всегда явно указывайте charset=utf-8, так как при передаче кириллицы (например, в адресах или именах) могут возникнуть проблемы с интерпретацией символов на стороне сервера.Мы выяснили причину сложности: необходимость управления кастомными SOAP-заголовками. Мы проанализировали ситуацию и нашли два пути решения. Первый путь — использование WSПараметрЗаголовка — является более элегантным и поддерживаемым, так как использует встроенные механизмы XDTO. Второй путь — прямой HTTP-запрос — дает максимальный контроль над отправляемыми данными и незаменим в сложных случаях интеграции.
Выбор метода зависит от стабильности работы WS-ссылки в вашей конфигурации. Попробуйте сначала реализовать обмен через WSПрокси, и только если платформа 1С будет выдавать недиагностируемые ошибки парсинга WSDL, переходите к ручному формированию HTTP-пакетов.