При разработке Web-сервисов в среде 1С:Предприятие разработчики часто сталкиваются с ситуацией, когда внешние системы (клиенты) присылают запросы, которые платформа отказывается принимать еще на этапе парсинга XML. Одной из самых коварных ошибок является "Namespace prefix soap on Header is not defined". Проанализируем, почему это происходит и как мы можем решить данную проблему, используя различные подходы.
Прежде всего, разберем структуру XML-пакета, который вызывает сбой. В корректном SOAP-запросе пространство имен (Namespace) должно быть четко определено для каждого префикса. Рассмотрим фрагмент "проблемного" кода, который присылает клиент:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Header>...</soap:Header>...</s:Envelope>
Проанализируем ситуацию: в корневом элементе Envelope объявлен префикс s, который соответствует стандарту SOAP. Однако дочерний элемент Header использует префикс soap. Согласно правилам именования в XML, любой префикс (в данном случае soap) должен быть предварительно объявлен с помощью атрибута xmlns:soap. Если этого объявления нет, парсер считает документ not well-formed (некорректно сформированным).
Важно понимать, что когда мы используем объект метаданных Web-сервис, за разбор входящего сообщения отвечает не наш код на встроенном языке, а внутренние механизмы платформы (модуль расширения веб-сервера). Платформа 1С строго следует стандартам XML и SOAP, поэтому "битый" пакет отсекается еще до того, как управление будет передано в процедуру веб-сервиса. Мы просто не успеваем перехватить управление, чтобы программно исправить текст.
Рассмотрим самый правильный, но не всегда возможный путь. Мы должны донести до разработчиков клиентской системы, что их XML-пакет нарушает стандарты. Для исправления ошибки клиент должен сделать одно из двух:
Envelope используется префикс s, то и заголовок должен называться <s:Header>.soap:Header, он обязан добавить объявление в корень: xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/".Если же иерархия организаций или технические ограничения не позволяют изменить формат запроса на стороне отправителя, перейдем к техническим решениям внутри 1С.
Как справедливо отмечено в обсуждении, использование HTTP-сервисов вместо Web-сервисов дает разработчику полный контроль над входящим потоком данных. В HTTP-сервисе мы получаем "сырое" тело запроса в виде строки или двоичных данных и можем делать с ними что угодно.
Разберем по шагам, как реализовать обработку такого запроса:
HTTP-сервис.POST.Посмотрим на пример кода, который позволяет обойти проблему с префиксами:
Функция ЛюбойМетодPOST(Запрос)
// Получаем тело запроса как строку
ТекстЗапроса = Запрос.ПолучитьТелоКакСтроку();
// Исправляем некорректные префиксы "на лету"
// Например, если мы знаем, что клиент присылает soap:Header без объявления,
// заменим его на корректный префикс s:Header, который объявлен в Envelope
ТекстИсправленный = СтрЗаменить(ТекстЗапроса, "soap:Header", "s:Header");
ТекстИсправленный = СтрЗаменить(ТекстИсправленный, "soap:Body", "s:Body");
// Теперь можем спокойно читать XML
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ТекстИсправленный);
// Используем XDTO для разбора логической части (Body)
Попытка
ДанныеXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
// Обработка логики...
Исключение
// Обработка ошибок парсинга
КонецПопытки;
Возврат Новый HTTPСервисОтвет(200);
КонецФункции
Этот метод является универсальным, так как позволяет обрабатывать даже самые экзотические ошибки в структуре XML, которые стандартный Web-сервис просто "выплевывает".
Если проблема не только в префиксах, но и в том, что 1С "не видит" блок <wsse:Security>, нам необходимо правильно настроить XDTO-пакеты. По умолчанию 1С ожидает данные в Body, а заголовки (Headers) игнорирует или выдает ошибку, если они не описаны в метаданных.
Проанализируем ситуацию с WS-Security. Для того чтобы платформа корректно приняла заголовок, выполним следующие действия:
oasis-200401-wss-wssecurity-secext-1.0.xsd) в XDTO-пакеты вашей конфигурации.Web-сервиса добавим новый параметр.Входной.Истина.Security).После этих манипуляций платформа поймет, что блок Security в Header является легитимным элементом сообщения, и попытается сопоставить его с типом XDTO, а не выдаст ошибку о неизвестном элементе.
Если мы не хотим менять Web-сервис на HTTP-сервис (например, из-за большого количества уже написанной логики), можно использовать промежуточное звено. Рассмотрим схему с использованием веб-сервера IIS или Apache, на котором опубликован сервис 1С.
Мы можем написать простейший скрипт (на Python, PHP или использовать модуль URL Rewrite для IIS), который будет перехватывать входящий поток, выполнять String Replace (замену префиксов) и перенаправлять "чистый" запрос уже непосредственно в 1С. Таким образом, платформа 1С будет получать идеально сформированный XML, и ошибка Namespace prefix исчезнет.
Мы рассмотрели несколько способов решения проблемы. Подведем итог: если вы имеете влияние на сторону отправителя — требуйте исправления XML-пакета. Если запрос "зашит" в стороннее ПО, оптимальным выходом будет переход на HTTP-сервисы 1С, так как они позволяют гибко манипулировать текстом запроса через функции СтрЗаменить и ЧтениеXML, обходя строгие ограничения платформенного SOAP-парсера.