Работа с веб-сервисами в 1С через стандартный механизм WSПрокси часто преподносит сюрпризы в виде ошибок соответствия типов или количества параметров. Особенно часто это происходит при интеграции со сторонними системами (например, ERP-системами на Java), где WSDL-описание может трактоваться платформой 1С не совсем однозначно. В данной статье мы подробно разберем, почему возникает ошибка "Недостаточно фактических параметров", и рассмотрим способы «окультурить» передачу XML-пакетов в веб-сервис.
Рассмотрим ситуацию: у нас есть рабочий SOAP-запрос из SoapUI, и мы пытаемся вызвать аналогичный метод в 1С. Основная ошибка новичков заключается в попытке передать в метод WSПрокси готовую строку XML. Однако 1С ожидает либо набор параметров, соответствующих типам XSD, либо готовый объект XDTO.
Выясним причину ошибки "Недостаточно фактических параметров". Платформа 1С строго следит за тем, чтобы количество переданных аргументов в метод прокси соответствовало определению в WSDL. Если в WSDL-схеме указано 5 параметров, вы обязаны передать все 5, даже если в SoapUI часть из них не отображается (помечены как необязательные).
Проанализируем пример кода, который часто приводит к ошибке:
// Ошибка: попытка передать XML-строку целиком
Ответ = Прокси.getPurchasesByParams(СтрокаXML);
Чтобы решить эту проблему стандартными средствами, мы должны передать параметры по отдельности, либо создать объект типа XDTOОбъект. Если параметров много и часть из них может быть пустой, используйте значение Неопределено для пропуска необязательных аргументов.
Рассмотрим правильный подход к формированию запроса через фабрику XDTO. Этот способ является наиболее «правильным» с точки зрения архитектуры 1С, так как он использует типизацию и позволяет избежать ручного формирования XML-строк.
Разберем процесс по шагам:
Посмотрим на пример кода:
СвояФабрикаXDTO = Прокси.ФабрикаXDTO;
// Находим тип объекта в пространстве имен сервиса
ТипПараметра = СвояФабрикаXDTO.Тип("http://plugins.operday.ERPIntegration.crystals.ru/", "getPurchasesByParams");
КорневойОбъект = СвояФабрикаXDTO.Создать(ТипПараметра);
// Заполняем свойства объекта
КорневойОбъект.dateOperDay = "2019-04-22";
КорневойОбъект.shopNumber = 93;
// Если метод требует передачи самого объекта:
Результат = Прокси.getPurchasesByParams(КорневойОбъект);
// Если метод требует перечисления параметров через запятую:
Результат = Прокси.getPurchasesByParams(КорневойОбъект.dateOperDay, КорневойОбъект.shopNumber, Неопределено, Неопределено, Неопределено);
Важный момент: если платформа все равно сообщает о нехватке параметров, проверьте через отладчик состав операции: Прокси.ТочкаДоступа.Интерфейс.Операции.Найти("getPurchasesByParams").Параметры. Это поможет точно определить, сколько значений ждет система.
Иногда причина странного поведения WSПрокси кроется в устаревшем кэше метаданных. Если вы изменили состав параметров на стороне веб-сервиса, 1С может продолжать использовать старое описание из своего внутреннего хранилища.
Проанализируем ситуацию с кэшем. В типовых конфигурациях (на базе БСП) существует регистр сведений Кэш программных интерфейсов. Если данные в нем некорректны, 1С не увидит изменений в WSDL. Для исправления ситуации можно воспользоваться обработкой "Обновление вспомогательных данных" или вручную очистить указанный регистр.
Если стандартный WSПрокси категорически отказывается работать (например, из-за несовместимости схем или специфических требований к заголовкам SOAPAction), мы можем использовать объект HTTPСоединение. Это более надежный способ, чем использование устаревшего MSXML2.XMLHTTP через COM-соединение, так как он работает кроссплатформенно (в том числе под Linux) и быстрее.
Рассмотрим, как правильно сформировать и отправить SOAP-пакет вручную:
// Формируем тело запроса
ТекстЗапроса =
"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:plug=""http://plugins.operday.ERPIntegration.crystals.ru/"">
| <soapenv:Header/>
| <soapenv:Body>
| <plug:getPurchasesByParams>
| <dateOperDay>" + Формат(ДатаЗапроса, "ДФ=yyyy-MM-dd") + "</dateOperDay>
| <shopNumber>" + НомерМагазина + "</shopNumber>
| </plug:getPurchasesByParams>
| </soapenv:Body>
|</soapenv:Envelope>";
// Настраиваем соединение
Соединение = Новый HTTPСоединение("адрес_сервера", , Логин, Пароль);
// Настраиваем заголовки
Заголовки = Новый Соответствие();
Заголовки.Вставить("Content-Type", "text/xml; charset=utf-8");
Заголовки.Вставить("SOAPAction", "getPurchasesByOperDay"); // Важно: проверьте точное имя в WSDL
// Отправляем запрос
Запрос = Новый HTTPЗапрос("/путь_к_сервису", Заголовки);
Запрос.УстановитьТелоИзСтроки(ТекстЗапроса, КодировкаТекста.UTF8);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния = 200 Тогда
// Обрабатываем результат
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
// Далее используем ФабрикаXDTO.ПрочитатьXML или ручной разбор
Иначе
Сообщить("Ошибка вызова: " + Ответ.КодСостояния);
КонецЕсли;
Многие разработчики по старой привычке используют MSXML2.XMLHTTP. Мы рекомендуем отказаться от этого в пользу HTTPСоединение по нескольким причинам:
readyState, так как метод ОтправитьДляОбработки дождется ответа от сервера автоматически.Таким образом, если вы столкнулись с проблемой передачи XML в веб-сервис, сначала попробуйте передать все параметры (включая необязательные как Неопределено) через WSПрокси. Если это не помогает — смело переходите на ручное формирование пакета через HTTPСоединение, что гарантирует вам полный контроль над структурой отправляемых данных.