Как правильно подключить веб-сервис в 1С и проверить его доступность? Разбор типичных ошибок

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

Интеграция систем с помощью SOAP веб-сервисов в 1С — это мощный инструмент, однако у начинающих разработчиков этот процесс часто вызывает трудности. Ошибки авторизации, падение платформы с кодами ответов 400 или 500, а также зависание интерфейса — типичные спутники первых попыток работы с WSПрокси. В этой статье мы подробно разберем, как правильно организовать подключение к веб-сервису, обработать возможные исключения и проверить доступность сервиса без риска заморозить сеанс пользователя.

Почему возникают ошибки при подключении? Разбор причин

Проанализируем основные проблемы, с которыми сталкиваются разработчики при написании кода подключения к веб-сервисам:

  1. Неправильное формирование URL-адреса. Ошибки HTTP 400 (Bad Request) и HTTP 500 (Internal Server Error) при создании объекта WSОпределения часто возникают из-за того, что путь к WSDL-описанию сформирован некорректно. Например, если адрес источника или имя веб-сервиса получены с ошибкой (или вовсе вернули пустую строку), платформа пытается обратиться к несуществующему адресу вроде ?wsdl.
  2. Попытка обратиться к несуществующему методу прокси. Метод CalcLengthString, часто используемый в учебных статьях, не является универсальным методом для проверки связи. WSПрокси динамически создает методы на основе WSDL-схемы вашего веб-сервиса. Если в вашем сервисе нет функции CalcLengthString, вы получите ошибку "Значение не является значением объектного типа". Вызывать нужно только те методы, которые реально опубликованы в вашем веб-сервисе (например, ПолучитьОтчет).
  3. Ошибки аутентификации. Если веб-сервер (IIS или Apache) или сама база данных 1С требуют авторизации, необходимо передавать корректные имя пользователя и пароль как в WSОпределения, так и в свойства созданного WSПрокси.
  4. Зависание интерфейса при создании WSОпределения в цикле. Конструктор WSОпределения делает синхронный сетевой запрос для скачивания WSDL-схемы. Если удаленный сервер "лежит" или долго отвечает, ваша программа зависнет на стандартный таймаут операционной системы (который может достигать нескольких минут). В цикле опроса нескольких баз это абсолютно недопустимо.

Шаг 1. Исправляем получение параметров из базы данных

Выясним причину ошибки HTTP 400 из примера автора. Попытка получить адрес источника следующим образом:

АдресИсточника = Справочники.Константы.АдресИсточника.Описание; // Ошибка!

В платформе 1С не существует коллекции Справочники.Константы. Если вам нужно получить значение стандартной константы 1С, используйте менеджер констант. Рассмотрим правильный синтаксис:

АдресИсточника = Константы.АдресИсточника.Получить();

Если же в вашей конфигурации действительно создан справочник с именем "Константы" (что является крайне нерекомендуемым стилем разработки), то обращаться напрямую к менеджеру справочника для получения реквизита элемента нельзя. Сначала нужно найти конкретную ссылку (например, предопределенный элемент или через поиск), и только потом брать его реквизит.

Шаг 2. Разрабатываем надежную функцию получения WS-прокси

Для того чтобы детально понимать, на каком этапе происходит сбой (скачивание WSDL или авторизация на веб-сервисе), мы должны разделить создание определений и создание прокси, а также корректно обработать ошибки. Посмотрим на пример отказоустойчивой функции:


&НаСервере
Функция ПолучитьПроксиВебСервиса(АдресИсточника, URIИмен, ИмяВебСервиса, Логин, Пароль, Таймаут = 5) Экспорт
    
    // Формируем корректный URL для получения WSDL-описания
    АдресWSDL = СокрЛП(АдресИсточника);
    Если Не Прав(АдресWSDL, 1) = "/" Тогда
        АдресWSDL = АдресWSDL + "/";
    КонецЕсли;
    АдресWSDL = АдресWSDL + ИмяВебСервиса + "?wsdl";
    
    ИмяТочкиПодключения = ИмяВебСервиса + "Soap";
    
    Попытка
        // Создаем WSОпределения с явным указанием таймаута (доступно в 1С 8.3)
        Определения = Новый WSОпределения(АдресWSDL, Логин, Пароль, , Таймаут);
    Исключение
        ЗаписьЖурналаРегистрации("Интеграция.ВебСервисы", 
            УровеньЖурналаРегистрации.Ошибка, , , 
            "Ошибка создания WSОпределений для " + АдресWSDL + Символы.ПС + ОписаниеОшибки());
        Возврат Неопределено;
    КонецПопытки;
    
    Попытка
        // Создаем прокси на основе полученных определений
        Прокси = Новый WSProxy(Определения, URIИмен, ИмяВебСервиса, ИмяТочкиПодключения);
        Прокси.Пользователь = Логин;
        Прокси.Пароль = Пароль;
        Возврат Прокси;
    Исключение
        ЗаписьЖурналаРегистрации("Интеграция.ВебСервисы", 
            УровеньЖурналаРегистрации.Ошибка, , , 
            "Ошибка создания WSПрокси для " + ИмяВебСервиса + Символы.ПС + ОписаниеОшибки());
        Возврат Неопределено;
    КонецПопытки;
    
КонецФункции

Шаг 3. Легковесная проверка доступности перед созданием WSОпределения

Важный совет: Не создавайте тяжелый объект WSОпределения в цикле для проверки "жив ли сервис". Гораздо быстрее и правильнее отправить легкий пинг через HTTP-соединение с минимальным таймаутом. Если веб-сервер отвечает кодом 200 (OK) или даже 401 (Unauthorized — значит, сервер жив, просто нужна авторизация), только тогда мы тратим ресурсы на создание SOAP-соединения.

Рассмотрим, как реализовать такую проверку:


&НаСервере
Функция СерверДоступен(АдресИсточника, ИмяВебСервиса, Таймаут = 3)
    
    // Парсим адрес источника, чтобы выделить хост и путь
    // Для простоты примера предполагаем, что адрес начинается с http:// или https://
    Протокол = "";
    АдресОчищенный = АдресИсточника;
    
    Если Найти(АдресИсточника, "https://") > 0 Тогда
        Протокол = "https://";
        АдресОчищенный = Сред(АдресИсточника, 9);
    ИначеЕсли Найти(АдресИсточника, "http://") > 0 Тогда
        Протокол = "http://";
        АдресОчищенный = Сред(АдресИсточника, 8);
    КонецЕсли;
    
    // Разделяем хост и путь публикации
    ПозицияСлэша = Найти(АдресОчищенный, "/");
    Если ПозицияСлэша = 0 Тогда
        Хост = АдресОчищенный;
        Путь = "/" + ИмяВебСервиса + "?wsdl";
    Иначе
        Хост = Лев(АдресОчищенный, ПозицияСлэша - 1);
        Путь = Сред(АдресОчищенный, ПозицияСлэша) + "/" + ИмяВебСервиса + "?wsdl";
    КонецЕсли;
    
    // Настраиваем защищенное соединение, если используется https
    ЗащищенноеСоединение = Неопределено;
    Если Протокол = "https://" Тогда
        ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();
    КонецЕсли;
    
    Попытка
        HTTPСоединение = Новый HTTPСоединение(Хост, , , , , Таймаут, ЗащищенноеСоединение);
        HTTPЗапрос = Новый HTTPЗапрос(Путь);
        HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос);
        
        // Коды 200 (ОК) или 401 (Требуется авторизация) свидетельствуют о том, что веб-сервер работает
        Возврат (HTTPОтвет.КодСостояния = 200 Или HTTPОтвет.КодСостояния = 401);
    Исключение
        Возврат Ложь;
    КонецПопытки;
    
КонецФункции

Шаг 4. Обход списка веб-сервисов и заполнение таблицы на форме

Теперь объединим все части решения в один рабочий алгоритм. Мы будем обходить строки нашей таблицы значений (ТЗ), проверять доступность физического сервера быстрым запросом, и в случае успеха подключаться по SOAP и вызывать реальный метод веб-сервиса (например, простейший метод проверки авторизации или пинга, созданный в вашей базе-приемнике).


&НаСервере
Процедура ПроверитьДоступностьВебСервисовНаСервере()
    
    // Получаем базовый адрес из констант (правильный метод!)
    АдресСервиса = Константы.АдресИсточника.Получить(); 
    URIИмен = "http://www.mycompany.ru/integration"; // Укажите ваш URI пространства имен
    Логин = "Администратор";
    Пароль = "ВашПароль";
    
    Для Каждого Стр Из Объект.ТЗВебСервисов Цикл
        
        ИмяВебСервиса = Стр.ВебСервис; // Берем имя сервиса из строки ТЗ
        
        // Этап 1: Быстрый пинг веб-сервера
        Если Не СерверДоступен(АдресСервиса, ИмяВебСервиса, 3) Тогда
            Стр.Доступность = Ложь;
            Продолжить;
        КонецЕсли;
        
        // Этап 2: Попытка создания SOAP-соединения и вызова тестового метода
        Прокси = ПолучитьПроксиВебСервиса(АдресСервиса, URIИмен, ИмяВебСервиса, Логин, Пароль, 5);
        
        Если Прокси = Неопределено Тогда
            Стр.Доступность = Ложь;
            Продолжить;
        КонецЕсли;
        
        Попытка
            // ВНИМАНИЕ: Вызываем РЕАЛЬНЫЙ метод вашего веб-сервиса, а не шаблонный "CalcLengthString"
            // Рекомендуется сделать легковесную функцию Ping() в самом веб-сервисе базы-приемника
            РезультатВызова = Прокси.Ping(); 
            
            Если РезультатВызова = Истина Тогда
                Стр.Доступность = Истина;
            Иначе
                Стр.Доступность = Ложь;
            КонецЕсли;
        Исключение
            // Метод Ping не реализован или произошла внутренняя ошибка выполнения кода в базе-приемнике
            ЗаписьЖурналаРегистрации("Интеграция.ВебСервисы", 
                УровеньЖурналаРегистрации.Предупреждение, , , 
                "Не удалось выполнить метод Ping для сервиса " + ИмяВебСервиса + Символы.ПС + ОписаниеОшибки());
            Стр.Доступность = Ложь;
        КонецПопытки;
        
    КонецЦикла;
    
КонецПроцедуры

Подведем итоги

Для стабильной работы интеграций через веб-сервисы всегда придерживайтесь следующих правил:

← На главную