При интеграции 1С с внешними веб-сервисами разработчики часто сталкиваются с жесткими лимитами со стороны сервера. Одной из наиболее типичных проблем является ограничение на количество одновременных TCP-соединений с одного IP-адреса. Если в компании работают сотни сотрудников через единый шлюз (NAT), стандартный подход «создал соединение — отправил запрос — уничтожил объект» приводит к тому, что часть пользователей получает отказ в обслуживании. Разберем детально, почему это происходит и какими способами можно решить эту задачу, сохранив стабильность системы.
Рассмотрим ситуацию: объект HTTPСоединение создается в коде 1С непосредственно перед отправкой запроса. Хотя в языке 1С нет явного метода Закрыть(), физическое соединение разрывается либо при удалении объекта из памяти сборщиком мусора, либо по инициативе сервера. В условиях, когда 100 пользователей одновременно инициируют обмен, сервер видит 100 попыток установить TCP-сессию. Если на сервере стоит лимит (например, не более 10 соединений), 90% запросов завершатся ошибкой.
Проанализируем технический нюанс: даже если 1С закрывает объект, соединение на сетевом уровне часто переходит в состояние TIME_WAIT на стороне сервера или клиентской ОС на время от 30 до 120 секунд. В этот период порт считается занятым. Таким образом, даже последовательные вызовы от разных пользователей могут быстро «забить» лимит, если частота запросов высока.
Этот метод является наиболее надежным с точки зрения архитектуры 1С. Вместо того чтобы позволять каждому клиентскому сеансу напрямую обращаться к внешнему сервису, мы создаем «узкое горлышко» с контролируемым количеством потоков.
Разберем алгоритм реализации по шагам:
ОчередьЗапросовКСервису. В нем будем хранить параметры запроса (адрес, тело XML/JSON, заголовки) и статус обработки.HTTPСоединение и использует его многократно для обработки пачки записей из регистра.Посмотрим на пример кода воркера, работающего в бесконечном цикле:
Процедура ОбработкаОчередиЗапросов() Экспорт
ПараметрыСвязи = ПолучитьПараметрыПодключения();
Соединение = Новый HTTPСоединение(ПараметрыСвязи.Сервер, ПараметрыСвязи.Порт);
Пока Истина Цикл
ЗапросИзОчереди = ПолучитьНовоеЗаданиеИзРегистра();
Если ЗапросИзОчереди = Неопределено Тогда
Приостановить(2); // Ждем 2 секунды, если работы нет
Продолжить;
КонецЕсли;
Попытка
Ответ = Соединение.ОтправитьДляОбработки(ЗапросИзОчереди.HTTPЗапрос);
ЗаписатьРезультатВРегистр(ЗапросИзОчереди.Идентификатор, Ответ);
Исключение
// Если соединение разорвано по таймауту, пересоздаем его
Соединение = Новый HTTPСоединение(ПараметрыСвязи.Сервер, ПараметрыСвязи.Порт);
ЗаписатьОшибку(ЗапросИзОчереди.Идентификатор, ИнформацияОбОшибке());
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Этот подход гарантирует, что количество соединений никогда не превысит количество запущенных фоновых заданий, независимо от числа активных пользователей в системе.
Если архитектура приложения не позволяет использовать асинхронную очередь, мы можем попытаться минимизировать количество пересозданий объектов HTTPСоединение внутри одного пользовательского сеанса. Для этого воспользуемся модулем с повторным использованием возвращаемых значений.
Выясним причину эффективности этого метода: платформа 1С будет кэшировать объект HTTPСоединение. Пока кэш жив, новые вызовы функции будут возвращать тот же самый объект, что позволит WinHTTP (системной библиотеке) переиспользовать уже установленное TCP-соединение (механизм Keep-Alive).
Пример реализации в общем модуле с установленным свойством «Повторное использование возвращаемых значений: На время сеанса»:
Функция ПолучитьКэшированноеСоединение(КлючПараметров) Экспорт
Параметры = РасшифроватьПараметры(КлючПараметров);
Возврат Новый HTTPСоединение(Параметры.Сервер, Параметры.Порт, Параметры.Пользователь, Параметры.Пароль);
КонецФункции
Важный момент: Объекты HTTPСоединение не сериализуются, поэтому их нельзя хранить в параметрах сеанса или передавать между клиентом и сервером. Кэширование работает только в рамках одного контекста (например, только на сервере).
Если проблема стоит остро и стандартные средства 1С не помогают, рассмотрим промышленный подход с использованием Reverse Proxy или Forward Proxy. Установив внутри сети компании сервер Nginx, мы можем делегировать ему управление соединениями.
Проанализируем схему работы:
upstream и директивы keepalive.Пример части конфигурации 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С это будет выглядеть как обращение к локальному ресурсу без каких-либо лимитов, а внешняя сторона увидит стабильный поток запросов через фиксированное количество сессий.
Начиная с версии платформы 1С 8.3.18, появилась поддержка HTTP/2. Главное преимущество этого протокола — мультиплексирование. В отличие от HTTP/1.1, где для каждого одновременного запроса нужно отдельное соединение, HTTP/2 позволяет передавать десятки запросов параллельно внутри одного и того же TCP-соединения.
Чтобы воспользоваться этим, выполним следующие условия:
HTTP/2.HTTPСоединение в 1С платформа автоматически попытается использовать современный протокол, если он доступен.HTTP/2 само по себе может снизить потребность в количестве соединений в 10–20 раз, так как все запросы от одного сеанса гарантированно пойдут через один сокет.При использовании любого метода удержания соединения (кэширование или очередь) крайне важно правильно обрабатывать ситуацию «протухания» сессии. Если внешний сервер закроет соединение по таймауту (в вашем случае — 30 секунд), объект в 1С станет невалидным.
Рассмотрим правильный паттерн обработки:
Попытка
Ответ = Соединение.ВызватьHTTPМетод(Запрос);
Исключение
// Проверяем, не связана ли ошибка с разрывом соединения
// Если да — пересоздаем объект и пробуем еще один раз
Соединение = ОбновитьСоединение();
Ответ = Соединение.ВызватьHTTPМетод(Запрос);
КонецПопытки;
Подведем итог: для небольших систем достаточно переиспользовать объект HTTPСоединение в рамках модуля с повторным использованием значений. Для крупных инсталляций со 100+ рабочими местами единственным стабильным решением будет либо внедрение промежуточного прокси-сервера (Nginx/Go-сервис), либо реализация полноценной очереди запросов на стороне 1С через фоновые задания.