Как установить таймаут и настроить асинхронный HTTP-запрос в 1С:Предприятии 7.7?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При интеграции 1С:Предприятия 7.7 с внешними сервисами, веб-сайтами и API разработчики часто сталкиваются с проблемой зависания системы. Классический сценарий: отправляется HTTP-запрос, удаленный сервер по какой-то причине не отвечает (или отвечает слишком медленно), и вся база данных 1С «намертво» зависает в ожидании ответа. Пользователи не могут работать, а администраторам приходится принудительно завершать процесс 1cv7s.exe через диспетчер задач.

В этой статье мы подробно разберем, почему стандартное свойство timeout объекта MSXML2.XMLHTTP вызывает ошибку в 1С 7.7, и рассмотрим эффективные способы решения этой проблемы с помощью альтернативных COM-объектов, настройки таймаутов и реализации асинхронных запросов.

Почему не работает свойство xmlhttp.timeout в 1С 7.7?

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


xmlhttp = CreateObject("MSXML2.XMLHTTP");
xmlhttp.Open("GET", АдресСайта, 0);
xmlhttp.timeout = 300000; // Ошибка: Поле агрегатного объекта не обнаружено
xmlhttp.Send();

Попытка обратиться к свойству timeout напрямую приводит к аварийному завершению работы скрипта с ошибкой «Поле агрегатного объекта не обнаружено». Почему так происходит? Дело в том, что объект MSXML2.XMLHTTP ориентирован на работу в клиентских сценариях (в среде браузера Internet Explorer) и использует системную библиотеку WinINet. В старых версиях MSXML, поставляемых с операционными системами по умолчанию, данный COM-объект просто не предоставляет интерфейсу автоматизации свойства управления таймаутами напрямую. Он полностью подчиняется глобальным сетевым настройкам операционной системы и Internet Explorer. Изменить время ожидания программно из кода 1С для этого объекта невозможно.

Решение №1: Использование объекта MSXML2.ServerXMLHTTP

Для серверных сценариев, где крайне важен жесткий контроль времени отклика, корпорация Microsoft разработала специализированный объект — MSXML2.ServerXMLHTTP (рекомендуется использовать актуальную версию MSXML2.ServerXMLHTTP.6.0). Он работает на базе сетевого стека WinHTTP, который функционирует независимо от настроек браузера и оптимизирован для многопоточных серверных приложений.

У объекта ServerXMLHTTP есть мощный встроенный метод SetTimeouts, который позволяет детально настроить все этапы сетевого взаимодействия. Метод принимает четыре параметра, значения которых задаются в миллисекундах:

  1. resolveTimeout — максимальное время на сопоставление доменного имени сайта с его IP-адресом (DNS-разрешение).
  2. connectTimeout — максимальное время на установку TCP-соединения с целевым сервером.
  3. sendTimeout — лимит времени на непосредственную отправку данных запроса на сервер.
  4. receiveTimeout — лимит времени на ожидание и чтение пакетов ответа от сервера после отправки запроса.

Важное правило: вызов метода SetTimeouts обязательно должен происходить до вызова метода Open. В противном случае настройки не вступят в силу.

Рассмотрим пример правильной реализации HTTP-запроса с таймаутом в 1С 7.7:


// Создаем объект серверного HTTP-клиента версии 6.0
WinHTTP = СоздатьОбъект("MSXML2.ServerXMLHTTP.6.0");

// Устанавливаем лимиты времени: 
// DNS - 5 сек, Соединение - 10 сек, Отправка - 10 сек, Ожидание ответа - 30 сек.
WinHTTP.SetTimeouts(5000, 10000, 10000, 30000);

// Открываем синхронное соединение (третий параметр равен 0)
WinHTTP.Open("GET", "https://api.mysite.ru/data", 0);

// Обязательно оборачиваем вызов Send в конструкцию Попытка...Исключение
Попытка
    WinHTTP.Send();
    Статус = WinHTTP.Status;
    Если Статус = 200 Тогда
        Сообщить("Запрос успешно выполнен!");
        ТекстОтвета = WinHTTP.ResponseText;
    Иначе
        Сообщить("Сервер вернул код ошибки: " + Статус);
    КонецЕсли;
Исключение
    // Сюда управление передается, если превышен любой из таймаутов
    Сообщить("Произошел сбой при обмене данными!");
    Сообщить("Описание ошибки: " + ОписаниеОшибки());
КонецПопытки;

Решение №2: Использование WinHttp.WinHttpRequest.5.1

В современной практике разработки под 1С 7.7 наиболее надежным и рекомендуемым стандартом стал системный объект WinHttp.WinHttpRequest.5.1. Он предоставляет разработчику полный контроль над заголовками, куками, прокси-серверами, а также отлично поддерживает современные стандарты шифрования и протоколы безопасности (такие как TLS 1.2 и TLS 1.3), что критически важно при работе с современными сайтами.

Настройка таймаутов в WinHttpRequest выполняется аналогичным образом через метод SetTimeouts:


WinHttp = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
// Установка таймаутов в миллисекундах
WinHttp.SetTimeouts(5000, 5000, 10000, 10000);

Реализация псевдо-асинхронного запроса с помощью WaitForResponse

В среде 1С:Предприятия 7.7 нет встроенного механизма для обработки событий (callbacks) COM-объектов напрямую в коде конфигурации. Однако мы можем элегантно решить эту задачу с помощью асинхронного запуска запроса в связке с методом WaitForResponse объекта WinHttpRequest.

Как устроен этот подход по шагам:

  1. Мы инициируем запрос в асинхронном режиме. Для этого при вызове метода Open передаем число 1 (или значение Истина) в качестве третьего параметра.
  2. Вызываем метод Send(). Так как режим асинхронный, этот метод завершает свою работу мгновенно, не дожидаясь ответа от сервера и не блокируя интерфейс 1С.
  3. Затем мы вызываем метод WaitForResponse(ТаймаутВСекундах). Данный метод приостанавливает выполнение кода 1С, но строго на указанное в параметре количество секунд. Если ответ от сервера приходит быстрее — метод сразу же возвращает управление коду. Если сервер не ответил за отведенный срок — метод возвращает 0 (или Ложь), предотвращая вечное зависание системы.

Давайте посмотрим на практический пример реализации такой схемы:


WinHttp = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");

// Открываем запрос асинхронно (третий параметр равен 1)
АдресСайта = "https://api.mysite.ru/data";
WinHttp.Open("GET", АдресСайта, 1);

// Отправляем запрос (отрабатывает мгновенно)
WinHttp.Send();

// Задаем лимит ожидания в секундах
ЛимитОжиданияСекунд = 15;

Попытка
    // WaitForResponse возвращает -1 (Истина), если ответ успешно получен, 
    // и 0 (Ложь), если отведенное время истекло.
    РезультатОжидания = WinHttp.WaitForResponse(ЛимитОжиданияСекунд);
Исключение
    РезультатОжидания = 0;
    Сообщить("Ошибка ожидания: " + ОписаниеОшибки());
КонецПопытки;

Если РезультатОжидания = -1 Тогда
    // Ответ получен, обрабатываем его
    Статус = WinHttp.Status;
    Если Статус = 200 Тогда
        Сообщить("Данные успешно загружены!");
        ТекстОтвета = WinHttp.ResponseText;
    Иначе
        Сообщить("Ошибка сервера. Статус: " + Статус);
    КонецЕсли;
Иначе
    // Превышено время ожидания, принудительно обрываем соединение
    WinHttp.Abort();
    Сообщить("Сервер не ответил за " + ЛимитОжиданияСекунд + " сек. Запрос отменен!");
КонецЕсли;

Реализация полноценной асинхронности (без блокировки интерфейса)

Если вам требуется отправить тяжелый HTTP-запрос в фоне, чтобы пользователь мог продолжать комфортно работать с интерфейсом 1С (открывать журналы документов, проводить документы), пока идет загрузка данных, необходимо использовать событийный подход. Для этого нам понадобятся внешние компоненты, умеющие генерировать периодические события в 1С 7.7, например, FormEx или 1С++.

Суть алгоритма заключается в следующем:

  1. Мы объявляем HTTP-объект в глобальной переменной модуля формы или глобального модуля, чтобы он не уничтожался после завершения процедуры отправки.
  2. Инициируем асинхронный запрос через Open("GET", URL, 1) и делаем Send().
  3. Запускаем периодический таймер FormEx с интервалом, например, в 1000 миллисекунд (1 секунда).
  4. В предопределенной процедуре обработки ожидания таймера (например, ПриВнешнемСобытии или специализированном обработчике FormEx) мы опрашиваем свойство readyState нашего HTTP-объекта.
  5. Свойство readyState может принимать числовые значения от 0 до 4. Нам важно состояние 4 (COMPLETED), которое означает, что запрос полностью завершен и данные готовы к чтению.
  6. Параллельно в таймере мы ведем счетчик секунд. Если значение счетчика превысило наш лимит (например, 30 секунд), а readyState все еще не равен 4, мы принудительно вызываем метод Abort(), отключаем таймер и сообщаем пользователю об ошибке связи.

Такой подход требует подключения внешних библиотек класса ВК, но обеспечивает высочайший уровень эргономики работы пользователей с информационной базой.

Нюансы работы с HTTPS-соединениями и SSL-сертификатами

При переходе со стандартного MSXML2.XMLHTTP на объекты ServerXMLHTTP или WinHttpRequest разработчики иногда сталкиваются с тем, что запросы к защищенным HTTPS-ресурсам начинают падать с ошибками безопасности. Это происходит из-за различий в архитектуре этих объектов:

Чтобы обойти эту проблему при тестировании или при работе со внутренними сервисами, у которых нет официального доверенного сертификата, в объекте WinHttpRequest можно отключить проверку ошибок SSL. Для этого перед отправкой запроса необходимо установить специальную опцию под номером 4:


WinHttp = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
WinHttp.Open("GET", "https://test-server.local/api", 1);

// Опция 4 со значением 13056 указывает WinHTTP игнорировать любые ошибки сертификатов
// (истекший срок действия, несовпадение имени хоста, недоверенный центр сертификации)
WinHttp.Option(4, 13056);

WinHttp.Send();

Используйте эту опцию с осторожностью в продакшн-среде, так как отключение проверок безопасности делает трафик уязвимым для атак типа "Man-in-the-Middle" (человек посередине).

Резюмируя все вышесказанное: для простых синхронных запросов с жестким таймаутом в 1С 7.7 оптимально подходит объект MSXML2.ServerXMLHTTP.6.0 с настроенным SetTimeouts. Для более гибкого контроля задержек без полного зависания программы идеальным решением станет WinHttp.WinHttpRequest.5.1 в связке с асинхронным вызовом и методом контроля ожидания WaitForResponse.

← На главную