Как оптимизировать работу с HTTP-соединениями в 1С и обойти ограничения по количеству подключений с одного IP?

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

При интеграции 1С с внешними веб-сервисами разработчики часто сталкиваются с жесткими лимитами со стороны сервера. Одной из наиболее типичных проблем является ограничение на количество одновременных TCP-соединений с одного IP-адреса. Если в компании работают сотни сотрудников через единый шлюз (NAT), стандартный подход «создал соединение — отправил запрос — уничтожил объект» приводит к тому, что часть пользователей получает отказ в обслуживании. Разберем детально, почему это происходит и какими способами можно решить эту задачу, сохранив стабильность системы.

Анализ проблемы: почему стандартный подход не работает

Рассмотрим ситуацию: объект HTTPСоединение создается в коде 1С непосредственно перед отправкой запроса. Хотя в языке 1С нет явного метода Закрыть(), физическое соединение разрывается либо при удалении объекта из памяти сборщиком мусора, либо по инициативе сервера. В условиях, когда 100 пользователей одновременно инициируют обмен, сервер видит 100 попыток установить TCP-сессию. Если на сервере стоит лимит (например, не более 10 соединений), 90% запросов завершатся ошибкой.

Проанализируем технический нюанс: даже если 1С закрывает объект, соединение на сетевом уровне часто переходит в состояние TIME_WAIT на стороне сервера или клиентской ОС на время от 30 до 120 секунд. В этот период порт считается занятым. Таким образом, даже последовательные вызовы от разных пользователей могут быстро «забить» лимит, если частота запросов высока.

Решение 1: Централизованная очередь через фоновые задания

Этот метод является наиболее надежным с точки зрения архитектуры 1С. Вместо того чтобы позволять каждому клиентскому сеансу напрямую обращаться к внешнему сервису, мы создаем «узкое горлышко» с контролируемым количеством потоков.

Разберем алгоритм реализации по шагам:

  1. Создадим служебный регистр сведений ОчередьЗапросовКСервису. В нем будем хранить параметры запроса (адрес, тело XML/JSON, заголовки) и статус обработки.
  2. В клиентском коде вместо выполнения запроса будем записывать данные в этот регистр.
  3. Запустим ограниченное количество фоновых заданий (например, 5–8 воркеров), которые будут постоянно мониторить регистр.
  4. Каждое фоновое задание создает один объект HTTPСоединение и использует его многократно для обработки пачки записей из регистра.

Посмотрим на пример кода воркера, работающего в бесконечном цикле:


Процедура ОбработкаОчередиЗапросов() Экспорт
    ПараметрыСвязи = ПолучитьПараметрыПодключения();
    Соединение = Новый HTTPСоединение(ПараметрыСвязи.Сервер, ПараметрыСвязи.Порт);
    
    Пока Истина Цикл
        ЗапросИзОчереди = ПолучитьНовоеЗаданиеИзРегистра();
        Если ЗапросИзОчереди = Неопределено Тогда
            Приостановить(2); // Ждем 2 секунды, если работы нет
            Продолжить;
        КонецЕсли;
        
        Попытка
            Ответ = Соединение.ОтправитьДляОбработки(ЗапросИзОчереди.HTTPЗапрос);
            ЗаписатьРезультатВРегистр(ЗапросИзОчереди.Идентификатор, Ответ);
        Исключение
            // Если соединение разорвано по таймауту, пересоздаем его
            Соединение = Новый HTTPСоединение(ПараметрыСвязи.Сервер, ПараметрыСвязи.Порт);
            ЗаписатьОшибку(ЗапросИзОчереди.Идентификатор, ИнформацияОбОшибке());
        КонецПопытки;
    КонецЦикла;
КонецПроцедуры

Этот подход гарантирует, что количество соединений никогда не превысит количество запущенных фоновых заданий, независимо от числа активных пользователей в системе.

Решение 2: Переиспользование соединения в рамках сеанса

Если архитектура приложения не позволяет использовать асинхронную очередь, мы можем попытаться минимизировать количество пересозданий объектов HTTPСоединение внутри одного пользовательского сеанса. Для этого воспользуемся модулем с повторным использованием возвращаемых значений.

Выясним причину эффективности этого метода: платформа 1С будет кэшировать объект HTTPСоединение. Пока кэш жив, новые вызовы функции будут возвращать тот же самый объект, что позволит WinHTTP (системной библиотеке) переиспользовать уже установленное TCP-соединение (механизм Keep-Alive).

Пример реализации в общем модуле с установленным свойством «Повторное использование возвращаемых значений: На время сеанса»:


Функция ПолучитьКэшированноеСоединение(КлючПараметров) Экспорт
    Параметры = РасшифроватьПараметры(КлючПараметров);
    Возврат Новый HTTPСоединение(Параметры.Сервер, Параметры.Порт, Параметры.Пользователь, Параметры.Пароль);
КонецФункции

Важный момент: Объекты HTTPСоединение не сериализуются, поэтому их нельзя хранить в параметрах сеанса или передавать между клиентом и сервером. Кэширование работает только в рамках одного контекста (например, только на сервере).

Решение 3: Использование промежуточного прокси-сервера (Nginx)

Если проблема стоит остро и стандартные средства 1С не помогают, рассмотрим промышленный подход с использованием Reverse Proxy или Forward Proxy. Установив внутри сети компании сервер Nginx, мы можем делегировать ему управление соединениями.

Проанализируем схему работы:

  1. 1С отправляет все запросы на локальный адрес Nginx.
  2. Nginx настроен на работу с внешним SOAP-сервисом с использованием модуля upstream и директивы keepalive.
  3. Nginx поддерживает постоянно открытыми, например, ровно 10 соединений с целевым сервером.
  4. Запросы от 100 пользователей 1С выстраиваются в очередь внутри Nginx и передаются во внешний мир через эти 10 «труб» по мере их освобождения.

Пример части конфигурации Nginx:


upstream soap_backend {
    server external-service.com:443;
    keepalive 10; # Держим 10 соединений открытыми
}

server {
    listen 8080;
    location / {
        proxy_pass https://soap_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

Для 1С это будет выглядеть как обращение к локальному ресурсу без каких-либо лимитов, а внешняя сторона увидит стабильный поток запросов через фиксированное количество сессий.

Решение 4: Переход на протокол HTTP/2

Начиная с версии платформы 1С 8.3.18, появилась поддержка HTTP/2. Главное преимущество этого протокола — мультиплексирование. В отличие от HTTP/1.1, где для каждого одновременного запроса нужно отдельное соединение, HTTP/2 позволяет передавать десятки запросов параллельно внутри одного и того же TCP-соединения.

Чтобы воспользоваться этим, выполним следующие условия:

Рекомендации по обработке ошибок

При использовании любого метода удержания соединения (кэширование или очередь) крайне важно правильно обрабатывать ситуацию «протухания» сессии. Если внешний сервер закроет соединение по таймауту (в вашем случае — 30 секунд), объект в 1С станет невалидным.

Рассмотрим правильный паттерн обработки:


Попытка
    Ответ = Соединение.ВызватьHTTPМетод(Запрос);
Исключение
    // Проверяем, не связана ли ошибка с разрывом соединения
    // Если да — пересоздаем объект и пробуем еще один раз
    Соединение = ОбновитьСоединение(); 
    Ответ = Соединение.ВызватьHTTPМетод(Запрос);
КонецПопытки;

Подведем итог: для небольших систем достаточно переиспользовать объект HTTPСоединение в рамках модуля с повторным использованием значений. Для крупных инсталляций со 100+ рабочими местами единственным стабильным решением будет либо внедрение промежуточного прокси-сервера (Nginx/Go-сервис), либо реализация полноценной очереди запросов на стороне 1С через фоновые задания.

← На главную