Что делать, если 1С выдает ошибку при загрузке некорректного WSDL стороннего сервиса?

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

При разработке интеграционных решений между 1С:Предприятием и сторонними информационными системами (например, внешними CRM, ERP или веб-сервисами) разработчики регулярно сталкиваются с проблемой: при попытке импортировать файл описания веб-службы (WSDL) платформа 1С возвращает ошибку «Неверный формат». При этом разработчики стороннего ресурса уверяют, что их сервис полностью исправен, отлично открывается в браузере и без проблем импортируется в такие инструменты тестирования, как SoapUI.

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

Выясняем причину: разница в строгости парсеров XML

Для начала проанализируем ситуацию и поймем, почему возникает такое разногласие между системами. Инструменты вроде SoapUI, а также веб-библиотеки на языках PHP (SoapClient), Python (Zeep) или Java (JAX-WS) изначально проектировались с расчетом на максимальную «всеядность» и отказоустойчивость. Обнаружив неточности или мелкие несоответствия стандартам в WSDL-файле, они пытаются самостоятельно «достроить» недостающую логику, игнорируя предупреждения.

Платформа 1С:Предприятие работает принципиально иначе. Встроенный в нее парсер XML/XSD базируется на строгом соблюдении стандартов консорциума W3C и спецификации WS-I Basic Profile 1.1. Если схема WSDL содержит хотя бы минимальное отклонение от этих стандартов, 1С не будет пытаться угадать логику разработчиков стороннего сервиса, а мгновенно прервет операцию и выбросит исключение.

Рассмотрим наиболее типичные технические ошибки в сторонних WSDL-файлах, на которых «спотыкается» парсер 1С:

  1. Использование RPC/Encoded вместо Document/Literal. Многие устаревшие генераторы веб-сервисов (особенно на PHP) по умолчанию создают WSDL в формате rpc/encoded. Однако современные стандарты WS-I требуют обязательного применения стиля document/literal. Платформа 1С крайне плохо работает с кодированными типами данных.
  2. Некорректное описание массивов (SOAP-ENC:Array). Сторонние разработчики часто передают коллекции данных, используя тип Array из пространства имен http://schemas.xmlsoap.org/soap/encoding/. С точки зрения строгой схемы XSD, стандартного типа Array не существует. Корректный способ описания списков и массивов для 1С — это использование стандартной последовательности xsd:sequence с указанием атрибута maxOccurs="unbounded".
  3. Лишние политики безопасности (Policies). Веб-сервисы, разработанные на Java (например, в корпоративных системах Amdocs или Liferay), часто включают в тело WSDL-файла специфические теги политик безопасности (например, <wsp:Policy>). Парсер 1С не умеет обрабатывать эти конструкции «из коробки» и аварийно завершает работу.
  4. Ошибки импорта схем и некорректные пространства имен (Namespaces). Если в WSDL используется тег xsd:import, но в атрибуте schemaLocation указан невалидный или недоступный относительный URL-адрес, 1С не сможет загрузить типы данных. Также критичны пустые или дефолтные пространства имен (вроде tempuri.org), если они настроены некорректно.

Решение 1. Формируем аргументы для разработчиков сторонней системы

Если разработчики сторонней CRM настаивают на валидности своего сервиса, ссылаясь на его успешную работу в SoapUI, мы можем использовать их же инструмент для демонстрации ошибок. Дело в том, что в SoapUI встроен профессиональный инструмент проверки соответствия веб-сервисов международным стандартам. Выполним проверку по шагам:

  1. Запустим программу SoapUI и импортируем в нее спорный WSDL-файл.
  2. В дереве проектов найдем созданный интерфейс веб-службы.
  3. Нажмем правой кнопкой мыши по имени интерфейса и в контекстном меню выберем пункт "Check WS-I Compliance" (Проверить соответствие WS-I).
  4. Программа запустит глубокий анализ схемы и сформирует детальный HTML-отчет, в котором будут перечислены все предупреждения и ошибки несоответствия стандартам WS-I Basic Profile.

Полученный отчет содержит ссылки на конкретные строки спецификации W3C. Предоставим этот документ коллегам со стороны CRM — против анализа их собственного инструмента тестирования у них не останется аргументов.


Решение 2. Локальное исправление WSDL и переопределение точки подключения

Если процесс согласования изменений затягивается, а интеграцию нужно запускать прямо сейчас, применим самый популярный среди 1С-разработчиков обходной путь — локальную коррекцию схемы.

Разберем этот алгоритм по шагам:

  1. Откроем оригинальный WSDL-файл в любом браузере и сохраним его на локальный диск (или на сервер, где работает сервер 1С) под именем, например, service.wsdl.
  2. Если WSDL импортирует внешние XSD-схемы через теги xsd:import, скачаем их аналогичным образом и сохраним в ту же папку.
  3. Откроем сохраненный файл service.wsdl в текстовом или XML-редакторе (например, Notepad++ или XMLSpy) и вручную исправим проблемные места:
    • Удалим все блоки политик безопасности <wsp:Policy>...</wsp:Policy> и их упоминания.
    • Заменим конструкции soapenc:Array на стандартные последовательности XML.
    • В тегах xsd:import пропишем локальные пути к скачанным файлам схем вместо внешних интернет-ссылок.
  4. В конфигураторе 1С добавим новую WS-ссылку, указав путь к нашему локальному исправленному файлу service.wsdl. Платформа успешно импортирует корректную схему и создаст все необходимые типы данных 1С.
  5. При написании программного кода для вызова методов веб-службы инициализируем прокси-класс динамически. При этом обязательно укажем адрес реальной боевой веб-службы в качестве последнего параметра (точки подключения). Таким образом, структура данных будет считываться из нашего локального правильного файла, а сами запросы будут отправляться на боевой сервер CRM.

Посмотрим на пример реализации данного подхода в коде 1С:


// Определим пути к локальному файлу описания и параметры подключения
ПутьКЛокальномуWSDL = "C:\WSDL\fixed_service.wsdl";
АдресБоевогоСервиса = "https://crm.external-system.ru/api/soap/v1";
ИмяТочкиПодключения = "CrmSoapEndpoint";
ИмяСервиса          = "CrmService";
ПространствоИмен    = "http://crm.external-system.ru/soap/";

Попытка
    // Инициализируем определения из локально сохраненного и исправленного файла
    Определения = Новый WSОпределения(ПутьКЛокальномуWSDL);
    
    // Создаем прокси, переопределяя реальный адрес вызова
    Прокси = Новый WSПрокси(Определения, ПространствоИмен, ИмяСервиса, ИмяТочкиПодключения);
    Прокси.АдресВызова = АдресБоевогоСервиса;
    
    // Теперь мы можем вызывать любые методы веб-сервиса
    ПараметрЗапроса = Прокси.ФабрикаXDTO.Создать(Прокси.ФабрикаXDTO.Пакеты.Получить(ПространствоИмен).Получить("ClientRequest"));
    ПараметрЗапроса.ClientId = "100234";
    
    Результат = Прокси.GetClientData(ПараметрЗапроса);
    ПоказатьПредупреждение(, "Данные успешно получены для клиента: " + Результат.ClientName);
Исключение
    ЗаписатьЛогОшибок(ОписаниеОшибки());
    ВызватьИсключение "Не удалось выполнить интеграционный запрос к CRM. Обратитесь к администратору.";
КонецПопытки;

Решение 3. Полный отказ от SOAP-клиента 1С в пользу прямых HTTP-запросов

Рассмотрим ситуацию, когда WSDL-файл сторонней системы настолько запутать или поврежден, что его ручная правка занимает непозволительно много времени, а структура типов постоянно меняется. В этом случае лучшим и наиболее отказоустойчивым решением будет полный отказ от встроенных объектов 1С WSСсылки и WSПрокси.

Мы можем взаимодействовать с SOAP-сервисом напрямую, отправляя обычные текстовые POST-запросы с XML-конвертом (Envelope) внутри. Это избавит платформу 1С от необходимости парсить WSDL-схему перед каждым вызовом.

Разберем этот процесс по шагам:

  1. Откроем SoapUI, найдем нужный метод и скопируем сформированный XML-шаблон запроса (SOAP Envelope).
  2. В коде 1С динамически сформируем этот XML-пакет, подставив в него наши параметры. Для этого можно использовать как обычное сложение строк, так и объект ЗаписьXML.
  3. Настроим подключение через объект HTTPСоединение.
  4. Передадим XML-пакет методом POST, обязательно указав в заголовках тип контента text/xml; charset=utf-8 и, при необходимости, заголовок SOAPAction (его точное значение также можно скопировать из свойств запроса в SoapUI).
  5. Получим XML-ответ от сервера и разберем его с помощью объекта ЧтениеXML или ПостроительDOM.

Проанализируем пример кода, реализующий прямую отправку SOAP-запроса через HTTP-протокол:


// Сформируем тело SOAP-конверта с подстановкой параметров
ИдентификаторКлиента = "100234";
ТелоSOAP = 
"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:crm=""http://crm.external-system.ru/soap/"">
|   <soapenv:Header/>
|   <soapenv:Body>
|      <crm:GetClientData>
|         <crm:ClientId>" + ИдентификаторКлиента + "</crm:ClientId>
|      </crm:GetClientData>
|   </soapenv:Body>
|</soapenv:Envelope>";

// Настроим параметры HTTP-соединения с поддержкой шифрования SSL
СерверCRM = "crm.external-system.ru";
ПортCRM = 443;
SSLСоединение = Новый ЗащищенноеСоединениеOpenSSL();

HTTPСоединение = Новый HTTPСоединение(СерверCRM, ПортCRM, , , , 30, SSLСоединение);

// Создаем HTTP-запрос к точке обслуживания API
HTTPЗапрос = Новый HTTPЗапрос("/api/soap/v1");
HTTPЗапрос.Заголовки.Вставить("Content-Type", "text/xml; charset=utf-8");
HTTPЗапрос.Заголовки.Вставить("SOAPAction", "http://crm.external-system.ru/soap/GetClientData");
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоSOAP, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);

Попытка
    // Отправляем POST-запрос на сервер CRM
    HTTPОтвет = HTTPСоединение.ОтправитьДляОбъекта(HTTPЗапрос);
    
    Если HTTPОтвет.КодСостояния = 200 Тогда
        // Читаем полученный XML-ответ
        ТекстОтвета = HTTPОтвет.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
        
        Чтение = Новый ЧтениеXML;
        Чтение.УстановитьСтроку(ТекстОтвета);
        
        // Разбираем структуру XML для поиска нужного узла с данными
        Пока Чтение.Прочитать() Цикл
            Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.Имя = "ClientName" Тогда
                Чтение.Прочитать(); // Переходим к значению внутри тега
                ИмяКлиента = Чтение.Значение;
                Прервать;
            КонецЕсли;
        КонецЦикла;
        
        ПоказатьПредупреждение(, "Прямой HTTP-вызов выполнен успешно! Клиент: " + ИмяКлиента);
    Иначе
        ВызватьИсключение "Ошибка сервера CRM. Код ответа: " + HTTPОтвет.КодСостояния;
    КонецЕсли;
Исключение
    ЗаписатьЛогОшибок(ОписаниеОшибки());
    ВызватьИсключение "Ошибка передачи данных по HTTP-каналу.";
КонецПопытки;

Этот способ является наиболее универсальным и надежным («неубиваемым»). Даже если разработчики сторонней CRM кардинально изменят структуру своего WSDL или добавят туда несовместимые с 1С библиотеки шифрования, наш HTTP-запрос продолжит корректно отправлять структурированные XML-пакеты и принимать ответы, гарантируя бесперебойную работу интеграции.

← На главную