При интеграции 1С с внешними системами через SOAP Web-сервисы разработчики часто сталкиваются с жестким поведением платформы 1С:Предприятие. По умолчанию, когда операция Web-сервиса возвращает данные, платформа оборачивает результат в XML-тег <return>. Однако внешние системы, ранее интегрированные со сторонним ПО (например, на Java, .NET или PHP), могут ожидать специфическое имя тега (например, <GetAllWkCargoesResult> или <Items>). Платформа 1С напрямую не позволяет изменить имя возвращаемого тега в свойствах операции Web-сервиса.
В этой статье мы подробно рассмотрим причины такого поведения платформы и разберем четыре практических способа решения этой проблемы: от штатного изменения параметров метаданных до модификации ответов на веб-сервере.
Платформа 1С самостоятельно управляет сериализацией SOAP-сообщений на основе стандартов WSDL. Когда для операции Web-сервиса задается «Тип возвращаемого значения», это указывает платформе, что функция должна вернуть одно конкретное значение. Согласно внутренним алгоритмам платформы, это возвращаемое значение всегда упаковывается в элемент <return> внутри тела ответа (SOAP Body). Изменить это имя через свойства XDTO-пакета или настройки операции в конфигураторе невозможно, так как это поведение жестко зашито в платформу 1С.
Разберем подробнее, какие альтернативные подходы мы можем использовать для решения этой задачи.
Это самый чистый и элегантный способ избавиться от тега <return> средствами самой платформы 1С, без привлечения стороннего софта или написания сложных оберток.
Суть метода заключается в том, что мы отказываемся от использования возвращаемого значения функции Web-сервиса (делаем операцию процедурой, возвращающей void), а все данные передаем через Выходной параметр операции. Платформа 1С для выходных параметров использует их реальные имена в качестве XML-тегов в SOAP-ответе.
Разберем этот способ по шагам:
MyCustomResponseName).Возврат присвойте результат непосредственно переменной созданного параметра.Посмотрим на пример кода в модуле Web-сервиса:
Процедура ПолучитьДанные(КодМобильногоКомпьютера, MyCustomResponseName)
УстановитьПривилегированныйРежим(Истина);
УзелОбмена = ПланыОбмена.МобильноеПриложение.НайтиПоКоду(КодМобильногоКомпьютера);
Если УзелОбмена.Пустая() Тогда
ВызватьИсключение(НСтр("ru='Неизвестное устройство - '") + КодМобильногоКомпьютера);
КонецЕсли;
// Формируем пакет данных (например, XDTO-объект)
ДанныеПакета = ОбменМобильноеПриложениеОбщее.СформироватьЕдиныйПакетВыгрузки(УзелОбмена);
// Вместо возврата значения, присваиваем его выходному параметру
MyCustomResponseName = ДанныеПакета;
КонецПроцедуры
В результате вызова этой операции платформа сгенерирует следующий SOAP-ответ:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ПолучитьДанныеResponse xmlns="http://www.yourcompany.ru/mobi">
<MyCustomResponseName>
<!-- Здесь будут находиться сериализованные данные XDTO -->
</MyCustomResponseName>
</ПолучитьДанныеResponse>
</soap:Body>
</soap:Envelope>
Этот способ полностью решает проблему, сохраняя при этом все преимущества автоматической сериализации XDTO и контроля типов платформой 1С.
Если ваша конфигурация находится на поддержке, или вы не хотите менять структуру метаданных Web-сервиса, можно настроить модификацию XML-ответа «на лету» прямо на веб-сервере (Apache или IIS). Это надежное промышленное решение, работающее как прозрачный middleware (промежуточное ПО).
Для замены тегов в Apache используется стандартный модуль mod_substitute. Он позволяет проводить контекстную замену текста в теле HTTP-ответов по регулярным выражениям.
Выполним настройку по шагам:
httpd.conf подключен модуль LoadModule substitute_module modules/mod_substitute.so.<Directory> или <Location>) добавьте следующие директивы:
<Location "/BaseName/ws">
AddOutputFilterByType SUBSTITUTE text/xml application/soap+xml
Substitute "s|<return>|<MyCustomResponseName>|i"
Substitute "s|</return>|</MyCustomResponseName>|i"
</Location>
При такой настройке веб-сервер будет автоматически перехватывать ответы от 1С и заменять теги <return> на нужные вам значения перед отправкой клиенту.
На веб-сервере IIS аналогичная задача решается с помощью модуля URL Rewrite (модуль переписывания URL).
text/xml и укажите замену подстрок <return> на <MyCustomResponseName>.Когда мы меняем структуру XML-ответов сторонними средствами (например, через веб-сервер), динамически генерируемый файл описания сервиса (WSDL), доступный по адресу ...?wsdl, все еще будет содержать упоминание элемента name="return". Это может приводить к ошибкам валидации на стороне клиента.
Чтобы этого избежать, мы можем использовать статический WSDL-файл:
http://server/base/ws/service?wsdl.name="return" на имя вашего кастомного тега (например, name="MyCustomResponseName").service.wsdl и положите его в каталог публикации на веб-сервере.Выясним причину, почему разработчики часто выбирают HTTP-сервисы. Если вам требуется абсолютный контроль над структурой XML, включая пространства имен, заголовки SOAP-конверта и любые кастомные теги, идеальным решением будет отказ от использования встроенных SOAP Web-сервисов 1С в пользу HTTP-сервисов.
HTTP-сервисы в 1С не накладывают никаких ограничений на формат передаваемых данных. Вы можете вручную сформировать любой XML-документ (в том числе полностью повторяющий структуру SOAP) с помощью встроенного объекта ЗаписьXML и вернуть его как тело HTTP-ответа.
Проанализируем пример кода реализации SOAP-ответа через HTTP-сервис:
Функция ПолучитьДанныеHTTP(Запрос)
// Инициализируем запись XML в строку
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку("UTF-8");
// Формируем структуру SOAP вручную
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("soap:Envelope");
ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("soap", "http://schemas.xmlsoap.org/soap/envelope/");
ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("mobi", "http://www.yourcompany.ru/mobi");
ЗаписьXML.ЗаписатьНачалоЭлемента("soap:Body");
ЗаписьXML.ЗаписатьНачалоЭлемента("mobi:ПолучитьДанныеResponse");
// Формируем кастомный тег вместо return
ЗаписьXML.ЗаписатьНачалоЭлемента("mobi:MyCustomResponseName");
// Сюда мы можем записать данные XDTO или обычный XML-текст
ЗаписьXML.ЗаписатьТекст("Результат работы сервиса");
ЗаписьXML.ЗаписатьКонецЭлемента(); // MyCustomResponseName
ЗаписьXML.ЗаписатьКонецЭлемента(); // ПолучитьДанныеResponse
ЗаписьXML.ЗаписатьКонецЭлемента(); // soap:Body
ЗаписьXML.ЗаписатьКонецЭлемента(); // soap:Envelope
РезультатXML = ЗаписьXML.Закрыть();
// Формируем HTTP-ответ с корректным заголовком Content-Type
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-Type", "text/xml; charset=utf-8");
Ответ.УстановитьТелоИзСтроки(РезультатXML, КодировкаТекста.UTF8);
Возврат Ответ;
КонецФункции
Этот способ сложнее в реализации, так как требует ручной обработки входящих SOAP-запросов и парсинга XML, но он дает 100% гарантию совместимости с любыми внешними системами, независимо от их требований к именованию XML-элементов.
Мы рассмотрели несколько способов решения проблемы с навязанным тегом <return>. Наиболее рекомендуемым и простым в реализации является Способ 1 (выходные параметры), так как он выполняется полностью средствами конфигуратора 1С и не требует стороннего вмешательства. Если же менять конфигурацию нельзя, используйте Способ 2 (модификация на веб-сервере). В случаях экстремальных требований к формату XML отличным выбором станет переход на HTTP-сервисы (Способ 4).