Как выполнить запрос к API (Ozon) без BOM и решить ошибку SSL на платформе 1С 8.2?

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

При интеграции старых версий платформы 1С (в частности 8.2) с современными веб-сервисами, такими как Ozon, Wildberries или государственные порталы, разработчики часто сталкиваются с непреодолимыми, на первый взгляд, трудностями. В этой статье мы подробно разберем ситуацию, описанную в теме форума: попытка отправить JSON-запрос заканчивается неудачей, при этом возникают вопросы как с кодировкой (BOM), так и с безопасным соединением (SSL).

Мы проанализируем причины ошибки SSL connect error, выясним, почему стандартные методы 1С 8.2 не работают, и рассмотрим надежные способы решения задачи через системные компоненты Windows.

Диагностика проблемы: почему код не работает?

Рассмотрим исходную ситуацию. Разработчик пытается использовать штатный объект HTTPСоединение на платформе 8.2.19.130. Код выглядит следующим образом:


ssl = Новый ЗащищенноеСоединениеOpenSSL;
HTTPСоединение = Новый HTTPСоединение(СтруктураURI.Хост, СтруктураURI.Порт,,,,,ssl);
HTTPЗапрос = Новый HTTPЗапрос(Запрос);
// ... установка заголовков ...
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса, "CESU-8"); // Попытка убрать BOM
HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);

При выполнении этого кода возникает исключение с текстом "Ошибка работы с Интернет: SSL connect error". Давайте разберем по шагам, что здесь происходит не так.

  1. Проблема SSL/TLS: Это главная причина падения кода. Современные API (включая Ozon) требуют использования протокола шифрования TLS 1.2 или выше. Платформа 1С:Предприятие 8.2 использует устаревшие библиотеки OpenSSL, которые поддерживают только SSL 3.0 и TLS 1.0. Сервер Ozon просто разрывает соединение, так как считает его небезопасным.
  2. Проблема BOM (Byte Order Mark): Даже если бы соединение установилось, метод УстановитьТелоИзСтроки в старых платформах часто принудительно добавляет метку порядка байтов (EF BB BF) в начало строки при использовании UTF-8. Это делает JSON невалидным для многих парсеров. Использование кодировки "CESU-8" является "хаком", который не гарантирует правильную работу с Emoji и спецсимволами.

Решение 1: Обход проблемы SSL через системный компонент WinHttp

Поскольку заставить встроенный HTTPСоединение в 8.2 работать с TLS 1.2 невозможно без использования внешних прокси (например, stunnel), мы пойдем другим путем. Мы будем использовать системный COM-объект Windows, который умеет работать с современными протоколами безопасности (при условии, что сама операционная система обновлена).

Речь идет об объекте WinHttp.WinHttpRequest.5.1. Он использует криптографические возможности самой Windows. Если у вас установлена Windows Server 2012 R2, Windows 10 или Windows Server 2008 R2 с соответствующими патчами, этот метод сработает отлично.

Давайте напишем функцию, которая отправляет запрос через этот компонент:


Функция ОтправитьЗапросWinHttp(Адрес, Метод, Заголовки, ТелоЗапроса = "")
    
    WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
    
    // Настраиваем игнорирование ошибок сертификатов (для разработки)
    // В продакшене лучше настроить корневые сертификаты в ОС
    WinHttp.Option(4) = 13056; 
    
    Попытка
        WinHttp.Open(Метод, Адрес, 0); // 0 - синхронный режим
        
        // Устанавливаем заголовки
        Для Каждого КлючИЗначение Из Заголовки Цикл
            WinHttp.SetRequestHeader(КлючИЗначение.Ключ, КлючИЗначение.Значение);
        КонецЦикла;
        
        // Важно: для JSON всегда явно указываем кодировку
        WinHttp.SetRequestHeader("Content-Type", "application/json; charset=utf-8");
        
        // Отправка
        WinHttp.Send(ТелоЗапроса);
        
        Возврат WinHttp.ResponseText;
        
    Исключение
        Сообщить("Ошибка выполнения запроса: " + ОписаниеОшибки());
        Возврат Неопределено;
    КонецПопытки;

КонецФункции

Этот код решает проблему SSL connect error, так как перекладывает задачу шифрования на операционную систему.

Решение 2: Формирование JSON без BOM

Теперь разберем вторую часть задачи. Как передать в WinHttp.Send тело запроса в кодировке UTF-8, но гарантированно без BOM? В 1С 8.2 строки хранятся в UTF-16. При прямой передаче строки COM-объекту, Windows может перекодировать её корректно, но если мы хотим полного контроля, лучше подготовить двоичные данные или правильно сформированную строку через ADODB.Stream.

Однако, самый надежный способ для старых платформ — сформировать файл без BOM и отправить его, либо (что проще для WinHttp) правильно сконвертировать строку перед отправкой.

Рассмотрим способ с использованием ADODB.Stream. Этот объект позволяет нам записать текст в UTF-8, а затем "откусить" первые 3 байта (BOM), если они там появились.


Функция ПолучитьТелоБезBOM(ТекстJSON)
    
    Stream = Новый COMОбъект("ADODB.Stream");
    Stream.Type = 2; // adTypeText
    Stream.Charset = "utf-8";
    Stream.Open();
    
    // Записываем текст
    Stream.WriteText(ТекстJSON);
    
    // Переходим в начало и меняем тип на бинарный
    Stream.Position = 0;
    Stream.Type = 1; // adTypeBinary
    
    // Пропускаем первые 3 байта (BOM)
    Stream.Position = 3;
    
    // Считываем остаток (чистый UTF-8 без BOM)
    БинарныеДанные = Stream.Read();
    Stream.Close();
    
    Возврат БинарныеДанные;
    
КонецФункции

Важное примечание: Объект WinHttp.Send умеет принимать вариантный тип данных, содержащий массив байт (который возвращает ADODB.Stream). Таким образом, мы передаем в запрос не строку 1С, а уже готовый бинарный массив в правильной кодировке.

Комплексное решение: Собираем все вместе

Теперь объединим знания и напишем полный код обработки, который решает задачу автора темы: отправка запроса к Ozon API с платформы 8.2, с поддержкой SSL и отсутствием BOM.


Процедура ВыполнитьЗапросКOzon()
    
    // 1. Подготовка данных
    Client_Id = "ВашID";
    Api_Key = "ВашКлюч";
    Url = "https://api-seller.ozon.ru/v1/product/info"; // Пример адреса
    
    // Пример тела запроса JSON
    ТелоСтрокой = "{""product_id"": 123456}";
    
    // 2. Подготовка тела без BOM через ADODB
    Попытка
        Stream = Новый COMОбъект("ADODB.Stream");
        Stream.Mode = 3; // ReadWrite
        Stream.Type = 2; // adTypeText
        Stream.Charset = "utf-8";
        Stream.Open();
        
        Stream.WriteText(ТелоСтрокой);
        
        Stream.Position = 0;
        Stream.Type = 1; // adTypeBinary
        Stream.Position = 3; // Пропускаем BOM (EF BB BF)
        
        ТелоБинарное = Stream.Read();
        Stream.Close();
    Исключение
        Сообщить("Не удалось подготовить тело запроса: " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
    // 3. Отправка через WinHttp (поддержка TLS 1.2)
    Попытка
        WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
        WinHttp.Open("POST", Url, 0);
        
        // Установка заголовков Ozon
        WinHttp.SetRequestHeader("Client-Id", Client_Id);
        WinHttp.SetRequestHeader("Api-Key", Api_Key);
        WinHttp.SetRequestHeader("Content-Type", "application/json; charset=utf-8");
        
        // Отправка бинарных данных
        WinHttp.Send(ТелоБинарное);
        
        // Получение результата
        ОтветСтрокой = WinHttp.ResponseText;
        Сообщить("Ответ сервера: " + ОтветСтрокой);
        
    Исключение
        Сообщить("Ошибка соединения с Ozon: " + ОписаниеОшибки());
    КонецПопытки;

КонецПроцедуры

Альтернативный вариант: Использование Stunnel

Если по каким-то причинам использование COM-объектов невозможно (например, сервер 1С работает под Linux, хотя для версии 8.2 это редкость, или политики безопасности запрещают COM), существует второй путь, упомянутый в обсуждении — Stunnel.

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

  1. Вы устанавливаете утилиту Stunnel на тот же сервер, где работает сервер 1С.
  2. Настраиваете Stunnel так, чтобы он слушал локальный порт (например, 127.0.0.1:8888) и перенаправлял трафик на api-seller.ozon.ru:443.
  3. В коде 1С вы обращаетесь не к Ozon, а к localhost по обычному протоколу HTTP (без шифрования).

Пример настройки 1С для работы через Stunnel:


// Обращаемся к локальному порту, где висит Stunnel
HTTPСоединение = Новый HTTPСоединение("127.0.0.1", 8888); 
HTTPЗапрос = Новый HTTPЗапрос("/v1/product/info"); // Путь остается тем же
// ... заголовки ...
// В заголовке Host лучше указать реальный хост, хотя Stunnel (в режиме client = yes) подменит SNI
HTTPЗапрос.Заголовки.Вставить("Host", "api-seller.ozon.ru");

Однако даже при использовании Stunnel проблема с BOM при использовании метода УстановитьТелоИзСтроки останется, поэтому для формирования тела запроса все равно рекомендуется использовать подход с записью во временный файл или ADODB.Stream, если вы используете штатные методы 1С.

Резюме

Ошибка SSL connect error на платформе 8.2 вызвана несовместимостью версий протоколов безопасности. Попытки "поиграть" с кодировками тела запроса не решат проблему подключения.

Для стабильной работы интеграции на устаревших платформах мы рекомендуем:

  1. Использовать WinHttp.WinHttpRequest.5.1 для поддержки TLS 1.2 средствами Windows.
  2. Использовать ADODB.Stream для очистки тела запроса от BOM-маркеров.
  3. Убедиться, что на сервере установлены актуальные корневые сертификаты.
← На главную