При публикации баз 1С:Предприятия на веб-сервере IIS нередко возникает ситуация, когда для внешних подключений выделяется нестандартный порт (например, 8080 или 8888). При этом само WSDL-описание по адресу с портом успешно скачивается и открывается в браузере или SoapUI, однако при попытке вызвать любой метод веб-сервиса запрос зависает по таймауту либо завершается сетевой ошибкой. Проанализируем, почему это происходит и какими способами можно наладить стабильный обмен.
Разберем внутренний механизм генерации WSDL-схемы платформой 1С. Когда клиент обращается по URL с параметром ?wsdl, модуль расширения веб-сервера 1С (wsisapi.dll) формирует XML-описание сервиса динамически. Для заполнения конечной точки вызова методов в узле <soapbind:address location="..."> модуль считывает сетевые параметры, переданные веб-сервером.
Если на сетевом шлюзе настроена трансляция портов (Port Forwarding), при которой внешний нестандартный порт перенаправляется на стандартный 80-й порт IIS, либо в привязках (Bindings) сайта IIS не зафиксирован используемый порт, веб-сервер сообщает модулю 1С адрес без порта. В итоге клиент (1С:Предприятие, мобильное приложение или сторонний сервис) получает WSDL, внутри которого в качестве адреса выполнения запросов жестко прописан стандартный 80-й порт. В результате инициализация проходит успешно, а реальный вызов метода уходит на закрытый 80-й порт и отваливается по таймауту.
Рассмотрим программное решение на стороне клиента, если мы разрабатываем или дорабатываем конфигурацию 1С. Начиная с платформы 8.3.7, конструктор объекта WSПрокси позволяет явно передать фактический URL точки подключения пятым параметром. При этом значение атрибута location из WSDL-схемы полностью игнорируется платформой.
Посмотрим на пример создания прокси с явным переопределением порта:
// Создаем определение сервиса на основе WSDL
Определение = Новый WSОпределения("http://192.168.1.100:8080/Retail/ws/Exchange.1cws?wsdl", "Логин", "Пароль");
URIПространстваИмен = "http://www.company.ru/exchange";
ИмяСервиса = "ExchangeService";
ИмяТочкиПодключения = "ExchangeSoapPort";
РеальныйАдресСервиса = "http://192.168.1.100:8080/Retail/ws/Exchange.1cws";
// Передаем фактический URL в 5-й параметр конструктора
Прокси = Новый WSПрокси(Определение, URIПространстваИмен, ИмяСервиса, ИмяТочкиПодключения, РеальныйАдресСервиса, "Логин", "Пароль");
// Вызываем нужный метод сервиса
Результат = Прокси.ВыполнитьОбмен();
Аналогичным образом параметр Местоположение можно передать в метод WSСсылкаМенеджер.СоздатьWSПрокси(), если WSDL импортирован в дерево метаданных как статическая WS-ссылка.
Если требуется динамически изменить текст схемы перед передачей в WSОпределения, разберем, как скачать WSDL напрямую в оперативную память без промежуточного сохранения на диск:
ИмяСервера = "192.168.1.100";
НомерПорта = 8080;
ПутьКWSDL = "/Retail/ws/Exchange.1cws?wsdl";
// Инициализируем защищенное или обычное HTTP-соединение
Соединение = Новый HTTPСоединение(ИмяСервера, НомерПорта, "Логин", "Пароль");
Запрос = Новый HTTPЗапрос(ПутьКWSDL);
Ответ = Соединение.Получить(Запрос);
Если Ответ.КодСостояния = 200 Тогда
ТекстWSDL = Ответ.ПолучитьТелоКакСтроку();
// Заменяем адрес точки подключения на корректный с указанием порта
СтарыйАдрес = "location=""http://" + ИмяСервера + "/";
НовыйАдрес = "location=""http://" + ИмяСервера + ":" + Формат(НомерПорта, "ЧГ=") + "/";
ТекстWSDL = СтрЗаменить(ТекстWSDL, СтарыйАдрес, НовыйАдрес);
// Сохраняем во временный файл для построения WSОпределения
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("wsdl");
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.УстановитьТекст(ТекстWSDL);
ТекстовыйДокумент.Записать(ИмяВременногоФайла);
Определение = Новый WSОпределения(ИмяВременногоФайла, "Логин", "Пароль");
УдалитьФайлы(ИмяВременногоФайла);
Иначе
ВызватьИсключение "Не удалось получить WSDL: " + Ответ.КодСостояния;
КонецЕсли;
Когда в качестве клиента выступает закрытое мобильное приложение (например, «1С:Мобильная касса») или внешняя сторонняя система, код которой изменить невозможно, проблему необходимо решать на уровне веб-сервера. Рассмотрим по шагам возможные варианты:
wsisapi.dll автоматически сформирует правильный WSDL со всеми номерами портов.?wsdl, и автоматически заменять подстроку location="http://host/ на location="http://host:порт/ в теле отдаваемого XML.Listen и ServerName, подставляя порт в WSDL «из коробки».Важный вывод: для тиражных мобильных клиентов 1С единственным рабочим решением является устранение трансляции портов на уровне IIS или шлюза, в то время как для заказной разработки в 1С достаточно передать фактический адрес пятым параметром в конструктор WSПрокси.