Как сохранить HTTP-соединение и авторизацию в течение всего сеанса в 1С?

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

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

В этой статье мы подробно разберем, как устроена работа с сетевыми соединениями в платформе 1С, почему традиционная попытка «сохранить» объект соединения в памяти является ошибкой, и какие современные механизмы позволяют элегантно решить задачу сохранения сеанса. Для задач по циклическому получению данных из внешних источников часто применяется автоматический сбор файлов по протоколам HTTP и FTP.

Проблема «живучести» объекта HTTPСоединение

Первая идея, которая часто возникает у начинающих разработчиков — создать один раз объект HTTPСоединение, поместить его в глобальную переменную, ПараметрыСеанса или во ВременноеХранилище, а затем использовать по мере необходимости. Однако этот подход неосуществим по нескольким фундаментальным причинам.

  1. Невозможность сериализации. Объект HTTPСоединение относится к типу данных, которые не могут быть сериализованы. Это значит, что его физически невозможно записать в базу данных, передать в параметры сеанса или поместить во временное хранилище для последующего извлечения на другом сервере или в другом сеансе.
  2. Особенности клиент-серверного взаимодействия. Даже если мы объявим переменную на клиенте, реальные вызовы к внешним API по соображениям безопасности и производительности должны выполняться на сервере. При каждом серверном вызове контекст инициализируется заново, а локальные переменные сервера уничтожаются.

Как работает пул соединений (Connection Pooling) в 1С 8.3

На самом деле, пытаться принудительно удерживать сам объект HTTPСоединение в памяти нет никакой технической необходимости. Платформа 1С:Предприятие 8.3 берет на себя управление низкоуровневыми сетевыми сокетами.

Когда в коде вызывается конструктор Новый HTTPСоединение, платформа не выполняет каждый раз медленное физическое TCP-соединение и TLS-рукопожатие с удаленным сервером. Вместо этого она обращается к системному пулу соединений. Если к данному хосту уже было открыто соединение и его таймаут (keep-alive) на стороне сервера еще не истек, 1С автоматически переиспользует существующий сетевой сокет.

Таким образом, пересоздавать объект HTTPСоединение при каждом запросе — это стандартная, быстрая и абсолютно безопасная операция. Наша главная задача заключается не в сохранении самого соединения, а в сохранении состояния авторизации (кук или токенов) и их последующей передаче в новые запросы.

Способ 1. Автоматическое сохранение кук в рамках одного вызова

Если вся цепочка действий (авторизация, отправка запроса, получение данных) выполняется внутри одного серверного вызова (в рамках выполнения одной процедуры или функции), то объект HTTPСоединение самостоятельно справляется с сохранением сессии.

Проанализируем ситуацию: созданный экземпляр HTTPСоединение автоматически отслеживает заголовки Set-Cookie, которые присылает удаленный веб-сервер в ответ на запрос авторизации. Все последующие запросы, отправленные через этот же самый экземпляр объекта, будут автоматически содержать эти куки в своих заголовках. Разработчику не нужно предпринимать никаких дополнительных действий.

Способ 2. Ручной перенос Cookies между разными серверными вызовами

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

Разберем этот процесс по шагам:

  1. Выполняем запрос авторизации к сервису.
  2. Извлекаем полученные куки из заголовков ответа сервера (заголовок Set-Cookie).
  3. Сохраняем полученную строку кук в безопасное место (например, в ПараметрыСеанса или во ВременноеХранилище).
  4. При каждом последующем запросе создаем новый объект HTTPЗапрос и принудительно подставляем сохраненные куки в заголовок Cookie.

Рассмотрим подробнее пример кода, реализующий эту схему:


// Шаг 1. Авторизация и получение Cookies
Функция ВыполнитьАвторизациюИПолучитьКуки(АдресСервера, Логин, Пароль)
    Соединение = Новый HTTPСоединение(АдресСервера, , , , , 15, Новый ЗащищенноеСоединениеOpenSSL());
    Запрос = Новый HTTPЗапрос("/api/login");
    
    // Формируем тело запроса для авторизации (например, JSON)
    ДанныеАвторизации = Новый Структура;
    ДанныеАвторизации.Вставить("username", Логин);
    ДанныеАвторизации.Вставить("password", Пароль);
    
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, ДанныеАвторизации);
    СтрокаТела = ЗаписьJSON.Закрыть();
    
    Запрос.УстановитьТелоИзСтроки(СтрокаТела, КодировкаТекста.UTF8, ИспользованиеМаркераПоследовательностиБайтов.НеИспользовать);
    Запрос.Заголовки.Вставить("Content-Type", "application/json");
    
    Ответ = Соединение.ОтправитьДляОбработки(Запрос);
    
    Если Ответ.КодСостояния = 200 Тогда
        // Извлекаем куки из заголовков
        СтрокаКук = Ответ.Заголовки.Получить("Set-Cookie");
        Возврат СтрокаКук;
    Иначе
        ВызватьИсключение "Ошибка авторизации: " + Ответ.КодСостояния;
    КонецЕсли;
КонецФункции

После получения строки кук мы должны сохранить ее. Если авторизация должна действовать на протяжении всего сеанса работы пользователя в системе, лучшим выбором будет использование ПараметрыСеанса (предварительно создав параметр с типом Строка). Если же куки нужны только в рамках работы конкретной формы, можно использовать ВременноеХранилище, связав его с уникальным идентификатором формы (УИД), чтобы данные автоматически очистились при закрытии формы.

При выполнении последующих запросов мы извлекаем сохраненную строку кук и внедряем ее в заголовок нового запроса:


// Шаг 2. Выполнение последующего запроса с сохраненными куками
Функция ПолучитьДанныеСервиса(АдресСервера, ПутьКРесурсу, СохраненныеКуки)
    Соединение = Новый HTTPСоединение(АдресСервера, , , , , 15, Новый ЗащищенноеСоединениеOpenSSL());
    Запрос = Новый HTTPЗапрос(ПутьКРесурсу);
    
    // Подставляем сохраненные куки в заголовки нового запроса
    Если ЗначениеЗаполнено(СохраненныеКуки) Тогда
        Запрос.Заголовки.Вставить("Cookie", СохраненныеКуки);
    КонецЕсли;
    
    Ответ = Соединение.Получить(Запрос);
    Возврат Ответ.ПолучитьТелоКакСтроку();
КонецФункции

Способ 3. Авторизация на основе токенов (Bearer / JWT)

Современным стандартом разработки веб-сервисов является использование авторизационных токенов вместо традиционных сессионных кук. Этот подход наиболее устойчив к кратковременным разрывам связи и масштабированию серверной инфраструктуры веб-сервиса. По этой технологии работает и бесплатная обработка для загрузки данных Wildberries по API, которая получает сведения о продажах комиссионеров в типовые конфигурации.

Процесс работы с токенами выглядит следующим образом:

  1. Первичный запрос: При первой авторизации 1С отправляет учетные данные (логин и пароль или API-ключ) и получает в ответ временный токен доступа (access_token) и токен обновления (refresh_token).
  2. Хранение токенов: Короткоживущий токен доступа сохраняется в оперативной памяти или в ПараметрыСеанса. Долгоживущий токен обновления (или учетные данные для повторного получения токена) сохраняется в базе данных — например, в безопасном хранилище данных или в защищенном регистре сведений.
  3. Использование токена: При каждом запросе токен передается в заголовке Authorization со спецификацией Bearer.
  4. Обновление токена: Если при очередном запросе сервер возвращает ошибку авторизации (код 401 Unauthorized), код 1С автоматически выполняет фоновый запрос на обновление токена с помощью refresh_token, сохраняет новый токен и повторяет целевой запрос без вывода ошибок пользователю.

Посмотрим на пример формирования запроса с использованием токена:


Функция ВыполнитьЗапросСТокеном(АдресСервера, ПутьКРесурсу, ТокенДоступа)
    Соединение = Новый HTTPСоединение(АдресСервера, , , , , 15, Новый ЗащищенноеСоединениеOpenSSL());
    Запрос = Новый HTTPЗапрос(ПутьКРесурсу);
    
    // Передаем токен в заголовке Authorization
    Запрос.Заголовки.Вставить("Authorization", "Bearer " + ТокенДоступа);
    
    Ответ = Соединение.Получить(Запрос);
    Возврат Ответ;
КонецФункции

Подход с использованием временного хранилища (для коротких сессий)

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

При этом критически важно привязывать данные к уникальному идентификатору формы (УИД). Это гарантирует, что данные не будут удалены сборщиком мусора платформы раньше времени (по умолчанию время жизни данных во временном хранилище без привязки к форме составляет 20 минут), и будут автоматически очищены операционной системой при закрытии этой формы пользователем.

Проанализируем пример сохранения авторизационной структуры во временное хранилище:


// Сохранение авторизационных данных на сервере
АдресХранилища = ПоместитьВоВременноеХранилище(АвторизационныеДанные, УникальныйИдентификаторФормы);

Резюме и архитектурные рекомендации

Подводя итоги, сформулируем основные правила для разработчиков 1С при проектировании интеграций с веб-сервисами:

  1. Не пытайтесь сохранять сам объект HTTPСоединение. Платформа самостоятельно оптимизирует сетевые сокеты через встроенный пул соединений. Вы можете смело вызывать Новый HTTPСоединение при каждом запросе.
  2. Если веб-сервис поддерживает авторизацию по токенам (JWT, Bearer), всегда отдавайте предпочтение этому способу. Он надежнее, безопаснее и проще масштабируется.
  3. Если сервис работает исключительно на сессионных Cookies, реализуйте ручной перенос строки кук из заголовка Set-Cookie ответа авторизации в заголовки Cookie последующих запросов.
  4. Для хранения авторизационных данных в рамках сеанса пользователя используйте ПараметрыСеанса (для глобальных интеграций) или ВременноеХранилище с привязкой к УИД формы (для локальных задач).
← На главную