При интеграции старых версий платформы 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". Давайте разберем по шагам, что здесь происходит не так.
УстановитьТелоИзСтроки в старых платформах часто принудительно добавляет метку порядка байтов (EF BB BF) в начало строки при использовании UTF-8. Это делает JSON невалидным для многих парсеров. Использование кодировки "CESU-8" является "хаком", который не гарантирует правильную работу с Emoji и спецсимволами.Поскольку заставить встроенный 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, так как перекладывает задачу шифрования на операционную систему.
Теперь разберем вторую часть задачи. Как передать в 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: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Если по каким-то причинам использование COM-объектов невозможно (например, сервер 1С работает под Linux, хотя для версии 8.2 это редкость, или политики безопасности запрещают COM), существует второй путь, упомянутый в обсуждении — Stunnel.
Суть метода заключается в следующем:
127.0.0.1:8888) и перенаправлял трафик на api-seller.ozon.ru:443.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 вызвана несовместимостью версий протоколов безопасности. Попытки "поиграть" с кодировками тела запроса не решат проблему подключения.
Для стабильной работы интеграции на устаревших платформах мы рекомендуем:
WinHttp.WinHttpRequest.5.1 для поддержки TLS 1.2 средствами Windows.ADODB.Stream для очистки тела запроса от BOM-маркеров.