Как исправить ошибку «Не могу установить соединение» при вызове веб-сервиса, если в WSDL указан локальный IP-адрес?

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

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

Давайте разберем по шагам причину возникновения этой ситуации и подробно рассмотрим все возможные пути ее решения — от простых программных методов до инфраструктурных настроек.

Выясняем причину ошибки

Секрет кроется в самом устройстве протокола SOAP и структуре файла WSDL. Когда мы инициализируем подключение, платформа 1С скачивает файл XML-описания (WSDL) по внешнему адресу. Однако внутри этого файла, в самом конце, находится секция описания портов и точек подключения <soap:address location="..." />.

Зачастую администраторы стороннего веб-сервиса публикуют его внутри своей корпоративной сети и просто пробрасывают порт наружу. При этом сам веб-сервер «не знает» своего внешнего адреса и при генерации WSDL-файла жестко прописывает туда свой внутренний (локальный) IP-адрес (например, http://192.168.1.50/ws/service или локальное имя сервера в их сети).

В результате происходят следующие процессы:

  1. Платформа 1С успешно скачивает схему WSDL с внешнего (правильного) адреса.
  2. При вызове метода веб-сервиса 1С обращается к свойству Прокси.ТочкаПодключения.Местоположение, куда подставляется адрес из скачанного файла (тот самый внутренний IP).
  3. Платформа пытается отправить SOAP-пакет на локальный адрес чужой сети и ожидаемо выдает ошибку «Не могу установить соединение».

Попытка напрямую перезаписать свойство Прокси.ТочкаПодключения.Местоположение = "..." в коде 1С не увенчается успехом, так как это свойство доступно только для чтения. Тем не менее, у нас есть несколько отличных способов обойти это ограничение.

---

Решение 1. Использование скрытого параметра конструктора Новый WSПрокси (Рекомендуется)

Мало кто знает, но стандартный конструктор объекта WSПрокси в платформе 1С:Предприятие поддерживает необязательный 8-й параметр, который позволяет принудительно переопределить адрес точки подключения, полностью проигнорировав некорректный адрес из WSDL-файла.

Полный синтаксис конструктора выглядит так:

Новый WSПрокси(<Определения>, <ПространствоИмен>, <ИмяСервиса>, <ИмяТочкиПодключения>, <ИнтернетПрокси>, <Таймаут>, <ЗащищенноеСоединение>, <Местоположение>, <ИспользоватьАутентификациюОС>)

Проанализируем пример кода, в котором мы явно передаем правильный внешний адрес в качестве восьмого параметра:


// Создаем определения на основе внешнего WSDL-файла
Определения = Новый WSОпределения("http://внешний-хост.ru/service.wsdl");

// Указываем реальный внешний адрес отправки запросов в 8-м параметре
РеальныйАдресСервиса = "http://внешний-хост.ru/service-endpoint";

Прокси = Новый WSПрокси(
    Определения, 
    "http://namespace.uri", 
    "MyService", 
    "MyServicePort", 
    , // Прокси по умолчанию
    60, // Таймаут соединения
    , // Защищенное соединение по умолчанию
    РеальныйАдресСервиса // Наш спасительный параметр!
);

// Теперь вызов метода отработает корректно по внешнему адресу
Результат = Прокси.getGoodsCatalog(СтрокаBase64);

---

Решение 2. Использование механизмов БСП (Библиотеки стандартных подсистем)

Если разработка ведется в типовой конфигурации 1С, созданной на базе БСП, мы можем задействовать готовую функцию-обертку, которая берет на себя всю рутину по созданию и параметризации прокси-объектов. В структуре параметров подключения БСП предусмотрено отдельное свойство для подмены адреса.

Рассмотрим пример реализации через БСП:


ПараметрыПодключения = ОбщегоНазначения.ПараметрыПодключенияWSПрокси();
ПараметрыПодключения.АдресWSDL = "http://внешний-хост.ru/service.wsdl";
ПараметрыПодключения.URIПространстваИмен = "http://namespace.uri";
ПараметрыПодключения.ИмяСервиса = "MyService";
ПараметрыПодключения.ИмяТочкиПодключения = "MyServicePort";
ПараметрыПодключения.Таймаут = 60;

// Явно подменяем точку подключения внешним адресом
ПараметрыПодключения.Местоположение = "http://внешний-хост.ru/service-endpoint"; 

// Создаем прокси стандартным методом БСП
Прокси = ОбщегоНазначения.СоздатьWSПрокси(ПараметрыПодключения);
Результат = Прокси.getGoodsCatalog(СтрокаBase64);

---

Решение 3. Динамическая подмена адреса для статических WS-ссылок

В случаях, когда интеграция построена через дерево метаданных (объект конфигурации WS-ссылка), мы также можем гибко управлять адресом отправки запросов при инициализации соединения. Метод СоздатьWSПрокси() у статической ссылки поддерживает параметр местоположения на 7-й позиции.

Давайте посмотрим на пример программного кода:


// Для статических WS-ссылок параметр местоположения передается 7-м по счету
РеальныйАдресСервиса = "http://внешний-хост.ru/service-endpoint";

Прокси = WSСсылки.ИмяНашейСтатическойСсылки.СоздатьWSПрокси(
    "http://namespace.uri", 
    "MyService", 
    "MyServicePort", 
    , // Прокси
    60, // Таймаут 
    , // Защищенное соединение
    РеальныйАдресСервиса // Принудительное местоположение
);

Результат = Прокси.getGoodsCatalog(СтрокаBase64);

---

Решение 4. Скачивание и модификация файла WSDL «на лету»

Если по какой-то причине вы работаете на устаревшей версии платформы 1С, где вышеописанные параметры не отрабатывают должным образом, можно применить надежный и гибкий обходной маневр: программно скачать файл WSDL, заменить некорректные адреса в XML-коде на лету и загрузить измененный файл из локального кэша.

Давайте пошагово реализуем этот алгоритм в коде:


// Шаг 1. Настраиваем подключение для скачивания исходного файла
НТТРСоединение = Новый HTTPСоединение("внешний-хост.ru", , , , , 30);
Запрос = Новый HTTPЗапрос("/service.wsdl");
Ответ = НТТРСоединение.Получить(Запрос);

Если Ответ.КодСостояния = 200 Тогда
    
    // Получаем текст WSDL
    ТекстWSDL = Ответ.ПолучитьТелоКакСтроку();
    
    // Шаг 2. Заменяем внутренний IP стороннего сервера на их же внешний домен
    НеправильныйАдрес = "192.168.1.50:8080/ws_path";
    ПравильныйАдрес    = "внешний-хост.ru/ws_path";
    ТекстWSDL = СтрЗаменить(ТекстWSDL, НеправильныйАдрес, ПравильныйАдрес);
    
    // Шаг 3. Записываем модифицированный XML во временный файл на диске сервера
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("wsdl");
    ЗаписьТекста = Новый ЗаписьТекста(ИмяВременногоФайла, КодировкаТекста.UTF8);
    ЗаписьТекста.Записать(ТекстWSDL);
    ЗаписьТекста.Закрыть();
    
    // Шаг 4. Инициализируем соединение 1С, используя схему "file://"
    ПутьКФайлуСхемы = "file://" + СтрЗаменить(ИмяВременногоФайла, "\", "/");
    Определения = Новый WSОпределения(ПутьКФайлуСхемы);
    
    // Шаг 5. Создаем прокси. Теперь внутри схемы прописаны корректные адреса отправки!
    Прокси = Новый WSПрокси(Определения, "http://namespace.uri", "MyService", "MyServicePort");
    
    Результат = Прокси.getGoodsCatalog(СтрокаBase64);
    
    // Удаляем временный файл за собой
    Попытка
        УдалитьФайлы(ИмяВременногоФайла);
    Исключение
        // Игнорируем ошибку удаления временного файла
    КонецПопытки;
    
КонецЕсли;

---

Решение 5. Настройка на стороне веб-сервера (Nginx / Reverse Proxy)

Если у вас есть контакт со службой системного администрирования со стороны владельцев веб-сервиса, наиболее правильным архитектурным решением будет корректная настройка их веб-сервера (например, Nginx).

Для того чтобы веб-сервис генерировал WSDL с правильными внешними путями автоматически, администраторам сторонней системы необходимо выполнить следующие действия:

Применение любого из предложенных программных решений в коде 1С гарантирует стабильную интеграцию с веб-сервисом и избавит вас от необходимости разворачивать сложные VPN-туннели ради обхода некорректно сформированных WSDL-схем.

← На главную