Почему методы Web-сервиса 1С на нестандартном порту обращаются на 80-й порт и как это исправить?

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

При публикации баз 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. Явное указание местоположения в объекте WSПрокси

Рассмотрим программное решение на стороне клиента, если мы разрабатываем или дорабатываем конфигурацию 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-ссылка.

Способ 2. Программное получение и модификация WSDL-файла

Если требуется динамически изменить текст схемы перед передачей в 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: " + Ответ.КодСостояния;
КонецЕсли;

Способ 3. Исправление на уровне веб-сервера IIS и сети

Когда в качестве клиента выступает закрытое мобильное приложение (например, «1С:Мобильная касса») или внешняя сторонняя система, код которой изменить невозможно, проблему необходимо решать на уровне веб-сервера. Рассмотрим по шагам возможные варианты:

  1. Настройка сквозного порта (1-to-1): В диспетчере IIS откроем привязки (Bindings) сайта и назначим сайту именно тот нестандартный порт, по которому обращаются клиенты (например, 8080). В сетевом маршрутизаторе пробросим входящий порт 8080 на внутренний порт 8080 сервера IIS. В этом случае модуль wsisapi.dll автоматически сформирует правильный WSDL со всеми номерами портов.
  2. Использование IIS URL Rewrite (Outbound Rules): Если изменить порт сайта нельзя, установим официальное расширение URL Rewrite для IIS и настроим исходящее правило (Outbound Rule). Правило будет перехватывать ответы на запросы, содержащие ?wsdl, и автоматически заменять подстроку location="http://host/ на location="http://host:порт/ в теле отдаваемого XML.
  3. Использование веб-сервера Apache: Модуль расширения 1С для Apache корректно обрабатывает директивы Listen и ServerName, подставляя порт в WSDL «из коробки».

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

← На главную