При интеграции 1С:Предприятия 7.7 с внешними сервисами, веб-сайтами и API разработчики часто сталкиваются с проблемой зависания системы. Классический сценарий: отправляется HTTP-запрос, удаленный сервер по какой-то причине не отвечает (или отвечает слишком медленно), и вся база данных 1С «намертво» зависает в ожидании ответа. Пользователи не могут работать, а администраторам приходится принудительно завершать процесс 1cv7s.exe через диспетчер задач.
В этой статье мы подробно разберем, почему стандартное свойство timeout объекта MSXML2.XMLHTTP вызывает ошибку в 1С 7.7, и рассмотрим эффективные способы решения этой проблемы с помощью альтернативных COM-объектов, настройки таймаутов и реализации асинхронных запросов.
Давайте проанализируем типичный код, который часто пытаются использовать разработчики:
xmlhttp = CreateObject("MSXML2.XMLHTTP");
xmlhttp.Open("GET", АдресСайта, 0);
xmlhttp.timeout = 300000; // Ошибка: Поле агрегатного объекта не обнаружено
xmlhttp.Send();
Попытка обратиться к свойству timeout напрямую приводит к аварийному завершению работы скрипта с ошибкой «Поле агрегатного объекта не обнаружено». Почему так происходит? Дело в том, что объект MSXML2.XMLHTTP ориентирован на работу в клиентских сценариях (в среде браузера Internet Explorer) и использует системную библиотеку WinINet. В старых версиях MSXML, поставляемых с операционными системами по умолчанию, данный COM-объект просто не предоставляет интерфейсу автоматизации свойства управления таймаутами напрямую. Он полностью подчиняется глобальным сетевым настройкам операционной системы и Internet Explorer. Изменить время ожидания программно из кода 1С для этого объекта невозможно.
Для серверных сценариев, где крайне важен жесткий контроль времени отклика, корпорация Microsoft разработала специализированный объект — MSXML2.ServerXMLHTTP (рекомендуется использовать актуальную версию MSXML2.ServerXMLHTTP.6.0). Он работает на базе сетевого стека WinHTTP, который функционирует независимо от настроек браузера и оптимизирован для многопоточных серверных приложений.
У объекта ServerXMLHTTP есть мощный встроенный метод SetTimeouts, который позволяет детально настроить все этапы сетевого взаимодействия. Метод принимает четыре параметра, значения которых задаются в миллисекундах:
Важное правило: вызов метода 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;
Иначе
Сообщить("Сервер вернул код ошибки: " + Статус);
КонецЕсли;
Исключение
// Сюда управление передается, если превышен любой из таймаутов
Сообщить("Произошел сбой при обмене данными!");
Сообщить("Описание ошибки: " + ОписаниеОшибки());
КонецПопытки;
В современной практике разработки под 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);
В среде 1С:Предприятия 7.7 нет встроенного механизма для обработки событий (callbacks) COM-объектов напрямую в коде конфигурации. Однако мы можем элегантно решить эту задачу с помощью асинхронного запуска запроса в связке с методом WaitForResponse объекта WinHttpRequest.
Как устроен этот подход по шагам:
Open передаем число 1 (или значение Истина) в качестве третьего параметра.Send(). Так как режим асинхронный, этот метод завершает свою работу мгновенно, не дожидаясь ответа от сервера и не блокируя интерфейс 1С.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С++.
Суть алгоритма заключается в следующем:
Open("GET", URL, 1) и делаем Send().ПриВнешнемСобытии или специализированном обработчике FormEx) мы опрашиваем свойство readyState нашего HTTP-объекта.readyState может принимать числовые значения от 0 до 4. Нам важно состояние 4 (COMPLETED), которое означает, что запрос полностью завершен и данные готовы к чтению.readyState все еще не равен 4, мы принудительно вызываем метод Abort(), отключаем таймер и сообщаем пользователю об ошибке связи.Такой подход требует подключения внешних библиотек класса ВК, но обеспечивает высочайший уровень эргономики работы пользователей с информационной базой.
При переходе со стандартного MSXML2.XMLHTTP на объекты ServerXMLHTTP или WinHttpRequest разработчики иногда сталкиваются с тем, что запросы к защищенным HTTPS-ресурсам начинают падать с ошибками безопасности. Это происходит из-за различий в архитектуре этих объектов:
XMLHTTP использует настройки браузера Internet Explorer. Если вы ранее заходили на сайт через браузер, приняли самоподписанный сертификат или настроили прокси-сервер, этот объект автоматически подхватит данные настройки.ServerXMLHTTP и WinHttpRequest работают на уровне служб операционной системы. Они не используют кэш и настройки Internet Explorer конкретного пользователя. Поэтому, если удаленный сервер использует самоподписанный SSL-сертификат или цепочка сертификатов не является доверенной в операционной системе Windows, запрос завершится ошибкой валидации сертификата.Чтобы обойти эту проблему при тестировании или при работе со внутренними сервисами, у которых нет официального доверенного сертификата, в объекте 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.