Как развернуть веб-сервис 1С на основе готового SOAP-запроса и почему возникает ошибка 500

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

Разработка веб-сервисов в 1С обычно идет по классическому пути: программист создает объект Web-сервис, определяет его методы, параметры и типы XDTO, а затем платформа автоматически генерирует WSDL-описание. Однако в реальной практике часто встречается обратная задача: клиент (сторонняя система, часто на базе .NET или Java) уже имеет жестко заданный формат запроса и требует, чтобы наш сервис принимал данные именно в таком виде. При попытке реализовать такой «подгон» разработчики часто сталкиваются с неочевидными ошибками, включая самую распространенную — «Ошибка 500».

В этой статье мы подробно разберем, как правильно настроить веб-сервис 1С под существующий SOAP-запрос, проанализируем структуру XML и выясним, какие ограничения платформы 1С могут помешать успешной интеграции.

Анализ структуры SOAP-запроса

Рассмотрим пример запроса, который прислал клиент. На первый взгляд он кажется стандартным, но в нем скрыто несколько важных деталей, которые определяют логику настройки 1С:


 <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Header>
        <requestRootId xmlns="http://schemas.microsoft.com/application-insights">100100</requestRootId>
        <requestId xmlns="http://schemas.microsoft.com/application-insights">451289</requestId>
    </s:Header>
    <s:Body>
        <GetPrice xmlns="http://tempuri.org/">
            <priceRequest xmlns:a="http://schemas.datacontract.org/2004/07/com.Ordering"
                xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                <a:Currency>EUR</a:Currency>
                <a:CurReference>12345</a:CurReference>
                <a:CurNumber>843</a:CurNumber>
                <a:LocationCode>LocationCode1</a:LocationCode>
                <a:OrderType>Stock</a:OrderType>
                <a:Parts>
                    <a:Part>
                        <a:PartNumber>1825005</a:PartNumber>
                        <a:Quantity>1</a:Quantity>
                        <a:UnitOfMeasure>Piece</a:UnitOfMeasure>
                    </a:Part>
                </a:Parts>
            </priceRequest>
        </GetPrice>
    </s:Body>
</s:Envelope>

Важные моменты в этом запросе:

  1. Синтаксическая корректность: В исходном примере была допущена ошибка — тег <a:Parts> не был закрыт корректно (отсутствовал слеш). Перед началом настройки всегда проверяйте XML на валидность.
  2. Пространства имен (Namespaces): Обратите внимание на http://tempuri.org/ для метода и http://schemas.datacontract.org/... для данных. Это типичные пространства имен для сервисов на WCF (.NET). В 1С они должны совпадать символ в символ.
  3. SOAP-заголовки (Header): В запросе присутствуют идентификаторы для мониторинга (Application Insights). Это критический момент для платформы 1С.

Шаг 1. Создание XDTO-пакета и настройка пространств имен

Проанализируем ситуацию: чтобы 1С поняла структуру priceRequest, нам необходимо создать XDTO-пакет. Если у вас есть XSD-схема от клиента — это лучший вариант. Если нет, схему придется воссоздать вручную.

При создании пакета URI пространства имен должен быть в точности таким, как в запросе у элементов данных: http://schemas.datacontract.org/2004/07/com.Ordering. Любая опечатка или лишний слеш в конце строки приведет к тому, что 1С не сможет сопоставить входящий XML с типом данных XDTO, и вы получите ошибку десериализации.

Внутри пакета опишем тип объекта priceRequest со всеми свойствами (Currency, CurReference и т.д.). Помните, что для систем на .NET порядок следования полей часто имеет значение (обычно по алфавиту). Если порядок в вашем XDTO-пакете будет отличаться от присланного XML, платформа может выдать ошибку 500.

Шаг 2. Настройка объекта Web-сервис

Теперь перейдем к самому объекту Web-сервис в метаданных 1С:

  1. Имя пространства имен: Укажите http://tempuri.org/. Именно в этом пространстве находится сам метод GetPrice.
  2. Имя метода: Оно должно строго совпадать с тегом внутри s:Body, то есть GetPrice.
  3. Параметры: Создайте параметр priceRequest. В свойстве "Тип значения" выберите созданный ранее тип из XDTO-пакета.

Шаг 3. Проблема SOAP-заголовков (Headers)

Выясним причину, по которой даже при правильной настройке XDTO сервис может возвращать ошибку 500. Проблема кроется в блоке <s:Header>.

Особенности 1С: Платформа 1С при работе со стандартными объектами Web-сервисы нацелена на обработку только содержимого s:Body. Официально 1С крайне ограничена в работе с заголовками. Если вызывающая сторона (клиент) передает заголовки, 1С может их просто проигнорировать, но если в заголовках установлен атрибут mustUnderstand="1", или если сама структура конверта не соответствует ожиданиям парсера 1С, сервер вернет 500-ю ошибку еще до того, как управление будет передано в ваш программный код.

Рассмотрим варианты решения, если заголовки мешают работе:

  1. Попросить клиента убрать заголовки: Это самое простое, но не всегда возможное решение. Если заголовки используются для технического мониторинга (как в примере), клиент может их отключить.
  2. Перейти на HTTP-сервисы: Это наиболее надежный архитектурный подход в 1С для работы со сложными сторонними запросами.

Шаг 4. Альтернативное решение — использование HTTP-сервисов

Если стандартный Web-сервис 1С не справляется с десериализацией из-за специфических заголовков или структуры XML, мы рекомендуем использовать HTTP-сервисы. В этом случае вы берете на себя роль «ручного» обработчика SOAP-протокола.

Разберем алгоритм работы через HTTP-сервис:

  1. Создаем HTTP-сервис с шаблоном пути, имитирующим адрес веб-сервиса.
  2. В методе POST получаем тело запроса в виде строки или потока.
  3. Используем объект ЧтениеXML, чтобы распарсить конверт вручную.

Пример кода для обработки такого запроса в HTTP-сервисе:


Функция GetPricePost(Запрос)
    
    Чтение = Новый ЧтениеXML;
    Чтение.УстановитьСтроку(Запрос.ПолучитьТелоКакСтроку());
    
    // Пропускаем Envelope и Header, добираемся до Body
    Пока Чтение.Прочитать() Цикл
        Если Чтение.Имя = "GetPrice" И Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
            // Начинаем десериализацию данных из Body с помощью XDTO
            ДанныеRequest = ФабрикаXDTO.ПрочитатьXML(Чтение, ФабрикаXDTO.Тип("http://schemas.datacontract.org/2004/07/com.Ordering", "priceRequest"));
            Прервать;
        КонецЕсли;
    КонецЦикла;

    // Здесь ваша логика обработки данных
    // ...
    
    // Формируем ответ также в формате SOAP-конверта вручную
    ТекстОтвета = 
        "<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">" +
        "<s:Body>...</s:Body>" +
        "</s:Envelope>";
        
    Ответ = Новый HTTPСервисОтвет(200);
    Ответ.УстановитьТелоИзСтроки(ТекстОтвета);
    Возврат Ответ;
    
КонецФункции

Как отладить ошибку 500?

Если вы все же решили использовать стандартный веб-сервис и получаете 500, проанализируем ситуацию с помощью инструментов диагностики:

Итоги

Подведем итоги нашего разбора. Развертывание сервиса «от запроса» требует ювелирной точности в настройке XDTO-пакетов и пространств имен. Помните, что:

  1. Пространства имен в 1С и в XML должны совпадать до последнего символа.
  2. Наличие SOAP-заголовков — зона риска для 1С.
  3. Если стандартный веб-сервис «капризничает», использование HTTP-сервиса дает вам полный контроль над входящим XML и позволяет обойти любые ограничения платформенного парсера.
← На главную