Почему не удается подключиться к веб-сервису 1С из внешней сети через нестандартный порт?

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

При публикации баз 1С на веб-сервере Microsoft IIS и организации внешнего доступа через отдельный порт разработчики часто сталкиваются с ситуацией, когда схема WSDL успешно открывается в браузере по внешнему адресу, однако при попытке вызвать веб-сервис из кода 1С возникает ошибка: «При вызове веб-сервиса произошла ошибка. Неизвестная ошибка. Ошибка работы с Интернет: Не могу установить соединение». Проанализируем причину такого поведения и рассмотрим по шагам методы решения проблемы.

Физика возникновения проблемы

Выясним причину ошибки, разобрав поэтапно процесс взаимодействия клиента 1С с SOAP веб-сервисом:

  1. Получение WSDL-схемы: клиент отправляет HTTP-запрос по указанному адресу (например, http://test.ru:832/test1Cdb/ws/testnamepub.1cws?wsdl). Этот запрос проходит через роутер и веб-сервер, возвращая XML-документ с описанием сервиса.
  2. Определение точки вызова (Endpoint): при выполнении метода веб-сервиса платформа 1С берет целевой адрес не из исходной строки подключения, а из атрибута location тега <soap:address>, который содержится внутри полученного WSDL-файла.
  3. Асимметричный проброс портов: модуль расширения веб-сервера 1С (wsisapi.dll) генерирует адрес в location динамически, основываясь на заголовках и параметрах запроса, переданных от IIS. Если на сетевом шлюзе внешний порт 832 перенаправляется на стандартный локальный порт 80, IIS сообщает модулю 1С, что запрос поступил на порт 80. В результате в блоке <soap:address location="..."> формируется адрес без указания порта 832.
  4. Сбой соединения: клиент 1С пытается выполнить реальный SOAP-запрос по адресу из тега location (на стандартный порт 80), который из внешней сети недоступен или закрыт брандмауэром. В этот момент и возникает ошибка подключения.

Распространенным заблуждением является попытка прописать порт в URI пространства имен сервиса (targetNamespace). Пространство имен служит исключительно уникальным строковым идентификатором типов данных в XML-схеме, реальных сетевых запросов по нему платформа не делает, поэтому изменение URI проблему не решает.

Решение 1. Настройка симметричного проброса портов и привязок в IIS

Самым правильным и прозрачным решением является обеспечение сквозного использования одного и того же порта на всех участках сети:

  1. Настройка сайта в IIS: в диспетчере служб IIS откроем свойства сайта, на котором опубликована информационная база 1С. Перейдем в раздел «Привязки» (Bindings) и добавим привязку на нужный порт (например, 8080 или 832) для всех IP-адресов.
  2. Настройка роутера / фаервола: на внешнем маршрутизаторе настроим симметричный проброс (Port Forwarding): внешний порт 832 должен транслироваться на локальный порт 832 сервера с IIS, а не на 80-й.
  3. Перезапуск веб-сервера: выполним команду перезапуска IIS через командную строку с правами администратора: iisreset

После этого IIS будет передавать модулю 1С фактический номер порта, и генерируемый WSDL будет содержать правильный атрибут <soap:address location="http://test.ru:832/test1Cdb/ws/testnamepub.1cws"/>.

Решение 2. Использование локального WSDL-файла на стороне клиента 1С

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

Разберем по шагам реализацию данного механизма:

  1. Выгрузим WSDL-описание сервиса в файл или получим его текст с помощью HTTP-запроса.
  2. Заменим в тексте WSDL значение атрибута location, добавив необходимый внешний порт.
  3. Сохраним измененный WSDL во временный файл и передадим его в конструктор WSОпределения.

Посмотрим на пример кода на стороне клиента 1С:


// Получаем WSDL-схему через HTTP-запрос
HTTPЗапрос = Новый HTTPЗапрос("/test1Cdb/ws/testnamepub.1cws?wsdl");
HTTPСоединение = Новый HTTPСоединение("test.ru", 832, "Пользователь", "Пароль");
HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос);

Если HTTPОтвет.КодСостояния = 200 Тогда
    ТекстWSDL = HTTPОтвет.ПолучитьТелоКакСтроку();
    
    // Подменяем адрес точки подключения, подставляя внешний порт
    СтарыйАдрес = "http://test.ru/test1Cdb/ws/testnamepub.1cws";
    НовыйАдрес = "http://test.ru:832/test1Cdb/ws/testnamepub.1cws";
    ТекстWSDL = СтрЗаменить(ТекстWSDL, СтарыйАдрес, НовыйАдрес);
    
    // Сохраняем во временный файл
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("wsdl");
    ЗаписьТекста = Новый ЗаписьТекста(ИмяВременногоФайла, КодировкаТекста.UTF8);
    ЗаписьТекста.Записать(ТекстWSDL);
    ЗаписьТекста.Закрыть();
    
    // Создаем WSОпределения из локального файла
    Определения = Новый WSОпределения(ИмяВременногоФайла, "Пользователь", "Пароль");
    Прокси = Новый WSПрокси(Определения, "http://test.ru/ws/testname", "testnamepub", "testnamepubSoap");
    Прокси.Пользователь = "Пользователь";
    Прокси.Пароль = "Пароль";
    
    // Вызов метода веб-сервиса
    Результат = Прокси.ТестовыйМетод();
    
    УдалитьФайлы(ИмяВременногоФайла);
КонецЕсли;

Решение 3. Использование модуля URL Rewrite в IIS

Еще один вариант централизованного исправления — использование официального модуля URL Rewrite для IIS. В конфигурационном файле web.config опубликованной базы можно настроить правило исходящей перезаписи (Outbound Rule), которое перехватывает все ответы с WSDL и автоматически заменяет строку адреса на необходимую, добавляя нужный порт перед отправкой клиенту.

← На главную