Интеграция систем на платформе 1С:Предприятие со сторонними программными продуктами через веб-сервисы (SOAP/WSDL) — стандартная и крайне востребованная задача. Однако разработчики часто сталкиваются с ситуацией, когда на этапе инициализации подключения система «намертво» зависает или выдает нетипичные ошибки XML-схем. В этой статье мы подробно разберем, почему зависает конструктор WSОпределения, как бороться с отсутствием атрибута targetNamespace и что означает ошибка десериализации Incoming messages must have a body format of Raw.
Когда мы пишем в коде строку Определения = Новый WSОпределения(АдресWSDL);, платформа 1С выполняет синхронный сетевой запрос к удаленному серверу. Она пытается не просто скачать WSDL-файл, но и полностью проанализировать его структуру, включая импортируемые внешние XML-схемы (файлы с расширением .xsd). Если удаленный сервер перегружен, защищен брандмауэром, требует авторизации или имеет нестабильное интернет-соединение, процесс скачивания может затянуться. По умолчанию в 1С таймаут ожидания ответа сервера при отсутствии его явного указания может длиться слишком долго, что со стороны выглядит как зависание всей программы.
Давайте рассмотрим несколько эффективных способов решения этой проблемы.
Самый простой шаг, который убережет вашу систему от бесконечного ожидания — передача четвертого параметра (таймаута) в конструктор объекта WSОпределения. Рекомендуется устанавливать время ожидания в пределах от 5 до 10 секунд. Этого времени обычно более чем достаточно для загрузки конфигурационных файлов SOAP-сервиса при нормальной работе сети.
Проанализируем пример кода с явным указанием таймаута:
АдресWSDL = "http://example.com/service.svc?wsdl";
Логин = "Admin";
Пароль = "P@ssword";
Таймаут = 5; // Время ожидания в секундах
Попытка
Определения = Новый WSОпределения(АдресWSDL, Логин, Пароль, Таймаут);
Исключение
ЗаписьЖурналаРегистрации("Интеграция.ВебСервисы",
УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка при получении WS-определений: " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Не удалось подключиться к веб-сервису. Проверьте сетевое соединение.";
КонецПопытки;
Использование конструкции Попытка ... Исключение гарантирует, что даже если сервис будет недоступен, ваша программа не зависнет, а корректно обработает ошибку и продолжит работу или выведет информативное сообщение пользователю.
Если структура веб-сервиса статична и меняется редко, постоянное скачивание WSDL по сети при каждом вызове кода — не лучшая практика. Мы можем один раз сохранить файл описания сервиса и все зависимые XSD-схемы локально на диск сервера 1С (или в общий сетевой каталог) и обращаться к ним напрямую.
Для этого выполним следующие действия:
.wsdl.<xsd:import schemaLocation="..."/>), скачайте эти схемы и положите их в ту же папку, скорректировав пути в WSDL-файле на локальные.
ПутьКФайлу = "C:\WS_Cache\MyService.wsdl";
Определения = Новый WSОпределения(ПутьКФайлу);
Этот метод полностью исключает зависимость инициализации от сетевых задержек и повышает скорость работы системы в разы.
В платформе 1С существует встроенный механизм — объект метаданных WS-ссылки. Мы можем добавить внешнюю ссылку непосредственно в конфигураторе 1С. В этом случае WSDL-описание компилируется прямо в базу данных, и при обращении к сервису платформе не требуется выполнять предварительные запросы для разбора схемы по сети.
Иногда при попытке прочитать WSDL разработчик получает ошибку: Схема должна иметь атрибут targetNamespace. Выясним причину этой проблемы.
Платформа 1С строго следует отраслевым стандартам интеграции (в частности, требованиям WS-I Basic Profile). Согласно спецификации XML Schema, любая схема, объявляющая типы данных, должна определять целевое пространство имен через атрибут targetNamespace. Однако многие сторонние веб-сервисы (особенно написанные на PHP или .NET без явной настройки контрактов данных) генерируют нестрогие схемы, где этот атрибут опущен.
Браузеры и другие языки программирования могут прощать такие огрехи, но 1С считает такую схему невалидной.
Решение проблемы:
.xsd локально на жесткий диск.<xs:schema> или <schema>.targetNamespace, добавьте его вручную, присвоив уникальное значение, например: targetNamespace="http://tempuri.org/".WSОпределения.При интеграции со службами под управлением Microsoft WCF (Windows Communication Foundation) вы можете столкнуться с ошибкой десериализации запроса: Incoming messages must have a body format of Raw. Давайте разберемся, почему она возникает.
Эта ошибка генерируется на стороне удаленного Windows-сервера. Она указывает на то, что вызываемый эндпоинт (точка подключения) настроен на работу по протоколу REST (использует привязку webHttpBinding) и ожидает «сырые» (Raw) данные — например, чистый JSON или бинарный поток в теле HTTP-запроса.
Когда мы работаем через WSОпределения и WSПрокси, платформа 1С всегда формирует SOAP-конверт (обертывает параметры в XML-теги <soap:Envelope> и <soap:Body>). Полувив такой запрос, WCF-сервер не может его десериализовать и возвращает ошибку.
Существует два пути решения этой проблемы:
WSПрокси. Вместо этого следует использовать объекты HTTPСоединение и HTTPЗапрос, формируя тело запроса вручную.basicHttpBinding) и отдельно для REST. Уточните у разработчиков сервиса корректный URL-адрес, предназначенный именно для SOAP-интеграции.Для того чтобы сделать работу с веб-сервисами в вашей конфигурации максимально отказоустойчивой, рекомендуется реализовать универсальный программный интерфейс, умеющий работать как со статическими WS-ссылками, так и с динамическими URL-адресами, включая автоматическую поддержку безопасного соединения SSL (HTTPS) и таймаутов.
Рассмотрим готовую программную реализацию, которую можно разместить в общем модуле:
// Создает и возвращает объект WSПрокси с учетом возможных настроек безопасности и таймаутов
Функция СоздатьWSПрокси(АдресWSDL, Логин = Неопределено, Пароль = Неопределено, Таймаут = 10) Экспорт
Если СтрНайти(АдресWSDL, "?") = 0 Тогда
// Это имя статической WS-ссылки из метаданных конфигурации
WSСсылка = WSСсылки[АдресWSDL];
Определения = WSСсылка.ПолучитьWSОпределения();
Параметры = ПолучитьПараметрыWSПрокси(Определения);
Прокси = WSСсылка.СоздатьWSПрокси(
Параметры.URIПространстваИмен,
Параметры.ИмяСервиса,
Параметры.ИмяТочкиПодключения, , ,
Параметры.ЗащищенноеСоединение
);
Иначе
// Это динамический URL-адрес WSDL-описания
ЗащищенноеСоединение = ?(СтрНачинаетсяС(НРег(АдресWSDL), "https://"), Новый ЗащищенноеСоединениеOpenSSL, Неопределено);
Попытка
Определения = Новый WSОпределения(АдресWSDL, Логин, Пароль, Таймаут, , ЗащищенноеСоединение);
Исключение
ВызватьИсключение "Не удалось загрузить схему веб-сервиса: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
Параметры = ПолучитьПараметрыWSПрокси(Определения);
Прокси = Новый WSПрокси(
Определения,
Параметры.URIПространстваИмен,
Параметры.ИмяСервиса,
Параметры.ИмяТочкиПодключения,
Логин,
Пароль,
Параметры.ЗащищенноеСоединение,
Таймаут
);
КонецЕсли;
Возврат Прокси;
КонецФункции
// Вспомогательная функция для извлечения параметров структуры WSDL
Функция ПолучитьПараметрыWSПрокси(Определения)
Если Определения.Сервисы.Количество() = 0 Тогда
ВызватьИсключение "В предоставленном WSDL-описании отсутствуют доступные SOAP-сервисы.";
КонецЕсли;
Сервис = Определения.Сервисы[0];
Если Сервис.ТочкиПодключения.Количество() = 0 Тогда
ВызватьИсключение "У выбранного веб-сервиса нет активных точек подключения.";
КонецЕсли;
ТочкаПодключения = Сервис.ТочкиПодключения[0];
ПараметрыWSПрокси = Новый Структура;
ПараметрыWSПрокси.Вставить("URIПространстваИмен", Сервис.URIПространстваИмен);
ПараметрыWSПрокси.Вставить("ИмяСервиса", Сервис.Имя);
ПараметрыWSПрокси.Вставить("ИмяТочкиПодключения", ТочкаПодключения.Имя);
ПараметрыWSПрокси.Вставить("ЗащищенноеСоединение", ?(СтрНачинаетсяС(НРег(Сервис.URIПространстваИмен), "https://"), Новый ЗащищенноеСоединениеOpenSSL, Неопределено));
Возврат ПараметрыWSПрокси;
КонецФункции
Давайте проанализируем, как работает данный код. Функция СоздатьWSПрокси автоматически определяет тип переданного параметра. Если в строке адреса нет знака вопроса (что характерно для статических объектов метаданных), система берет определение из дерева конфигурации. Если же передан полноценный веб-адрес, создается безопасное соединение ЗащищенноеСоединениеOpenSSL (в случае использования протокола HTTPS) и инициализируется динамический объект WSОпределения с ограничением по времени ожидания.
Функция ПолучитьПараметрыWSПрокси избавляет разработчика от необходимости вручную прописывать URI пространства имен, имя сервиса и точку подключения — платформа считывает первый доступный элемент из структуры WSDL автоматически, что значительно упрощает поддержку кода при миграции сервисов на новые адреса.