При работе с внешними веб-сервисами, особенно опубликованными на нестандартных портах (отличных от 80 для HTTP и 443 для HTTPS), разработчики часто сталкиваются с ситуацией, когда файл описания WSDL доступен по ссылке, но при попытке вызова методов возникает ошибка подключения. Проанализируем ситуацию: если мы откроем текст WSDL в браузере и заглянем в секцию soap:address location, то можем обнаружить, что там указан адрес без порта или с неверным хостом. Это происходит потому, что платформа 1С при динамической генерации WSDL ориентируется на заголовки пришедшего HTTP-запроса, и если веб-сервер (например, IIS или Apache) настроен через проброс портов или реверс-прокси, информация о реальном порте может потеряться.
В данной статье мы разберем несколько способов решения этой проблемы: от «быстрого исправления» через локальный файл до архитектурно правильного переопределения точки подключения в коде 1С.
Выясним причину, по которой 1С генерирует некорректный атрибут location. Когда клиент запрашивает ?wsdl, расширение веб-сервиса 1С берет имя сервера и порт из HTTP-заголовка Host. Рассмотрим типичный случай: веб-сервер слушает порт 8080, но снаружи он опубликован через NAT как порт 80. Или наоборот: IIS работает на порту 80, а внешние запросы приходят на 8002. Если администратор не настроил корректную трансляцию заголовков, 1С «выплеснет» в WSDL внутренний адрес, к которому внешний клиент не сможет достучаться. В итоге объект WSОпределения создается успешно, но объект WSПрокси при попытке вызова метода будет ломиться по неверному адресу.
Это самый оперативный способ, если у вас нет доступа к настройкам веб-сервера. Суть метода заключается в том, чтобы скачать текст WSDL, программно заменить в нем строку адреса на правильную, сохранить во временный файл и загрузить определение уже из этого файла. Разберем по шагам, как это реализовать в коде.
Для начала нам необходимо получить текст описания сервиса. Мы можем сделать это обычным HTTP-запросом или загрузить из константы, если адрес меняется редко. После получения текста мы правим порт в узле location.
Посмотрим на пример реализации функции подключения:
Функция ПодключитьсяКСервисуСПомощьюФайла() Экспорт
// Получаем настройки
Логин = "Robot";
Пароль = "password";
// Допустим, мы заранее получили текст WSDL и сохранили в переменную WSDLТекст
WSDLТекст = ПолучитьТекстWSDLСервера();
// Путь к временному файлу
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
// Важный нюанс: 1С требует для протокола file:// использование прямых слешей
АдресДляОпределения = СтрЗаменить(ИмяВременногоФайла, "\", "/");
АдресДляОпределения = "file://" + АдресДляОпределения;
// Записываем исправленный WSDL (предполагается, что в WSDLТекст уже заменен адрес)
ТекстДок = Новый ТекстовыйДокумент();
ТекстДок.УстановитьТекст(WSDLТекст);
ТекстДок.Записать(ИмяВременногоФайла);
Попытка
// Создаем определение из локального файла
Определение = Новый WSОпределения(АдресДляОпределения, Логин, Пароль);
ПространствоИмен = "http://www.your-service.ru/Exchange";
Прокси = Новый WSПрокси(Определение, ПространствоИмен, "Service_Name", "Port_Name");
Прокси.Пользователь = Логин;
Прокси.Пароль = Пароль;
Возврат Прокси;
Исключение
ЗаписьЖурналаРегистрации("Ошибка подключения к WS", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
Важно: При использовании этого метода помните, что если ваш WSDL содержит импорты схем (тег xsd:import) с относительными путями, 1С не сможет их найти рядом с временным файлом в папке temp. В этом случае метод с файлом может выдать ошибку при создании объекта WSОпределения.
Мало кто знает, но в платформе 1С предусмотрен штатный механизм для решения этой проблемы без манипуляций с файловой системой. Мы можем загрузить WSОпределения по реальному URL (даже если внутри location кривой), а при создании WSПрокси явно указать, куда на самом деле нужно отправлять запросы.
Проанализируем параметры конструктора Новый WSПрокси. У него есть пятый параметр — ТочкаПодключения. Если мы передадим туда правильный URL с нужным портом, 1С проигнорирует тот адрес, который был прописан внутри WSDL.
Рассмотрим, как это выглядит на практике:
// 1. Создаем определение по реальному адресу (где лежит WSDL)
// Порт здесь нужен только для того, чтобы скачать сам XML файл описания
АдресWSDL = "http://192.168.1.10:8002/base/ws/service.1cws?wsdl";
Определение = Новый WSОпределения(АдресWSDL, Логин, Пароль);
// 2. Определяем параметры сервиса
ПространствоИмен = "http://www.fixinchik.ru/ClientsExchange";
ИмяСервиса = "_ОбменКонтрагентами";
ИмяПорта = "_ОбменКонтрагентамиSoap";
// 3. Явно задаем адрес, по которому будут уходить SOAP-запросы
// Именно здесь мы исправляем порт, если он в WSDL указан неверно
РеальныйАдресСервиса = "http://192.168.1.10:8002/base/ws/service.1cws";
// 4. Создаем прокси с указанием точки подключения
Прокси = Новый WSПрокси(Определение, ПространствоИмен, ИмяСервиса, ИмяПорта, РеальныйАдресСервиса);
Прокси.Пользователь = Логин;
Прокси.Пароль = Пароль;
Этот метод является наиболее предпочтительным, так как он не требует работы с временными файлами, не ломает импорты XSD-схем и полностью соответствует логике работы со стеком протоколов SOAP.
Если вы сами являетесь разработчиком сервиса на стороне 1С, лучше устранить причину, а не следствие. Проанализируем настройки IIS. Если веб-сервис работает на порту 8080, убедитесь, что в файле default.vrd в параметре base или в настройках сайта в IIS не указаны жесткие перенаправления, отрезающие порт.
Основные рекомендации для системного администратора:
Host: proxy_set_header Host $host:$server_port;.Если после всех манипуляций подключение все равно не устанавливается, рекомендуем выполнить следующие действия:
location (тот, что вы правили) в обычном браузере на сервере, где запущена 1С.WSОпределения. После изменения порта на сервере или в коде, обязательно перезапустите сеанс или обновите конфигурацию (если используете WS-ссылки в дереве метаданных).WSDL слишком сложна и не поддается правке, можно отказаться от WSПрокси. Используйте объект HTTPСоединение и метод ОтправитьДляОбъекта, вручную сформировав SOAP Envelope. Это даст вам 100% контроль над тем, по какому порту и адресу уйдет пакет.Подводя итог, можно сказать, что проблема нестандартного порта в WSDL — это классическая проблема инфраструктуры, которая легко обходится в 1С либо через временное сохранение файла с исправлением текста, либо (что лучше) через явное указание адреса точки подключения в конструкторе WSПрокси.