Почему POST-запрос в толстом клиенте возвращает ошибку 400, хотя в тонком клиенте всё работает корректно?

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

При интеграции 1С с внешними веб-сервисами программисты часто сталкиваются с ситуацией, когда один и тот же код ведет себя по-разному в зависимости от клиента или режима совместимости конфигурации. Типичный сценарий: в современной конфигурации на управляемых формах (например, УТ 11) запрос проходит успешно, а в старой конфигурации на обычных формах (например, УТ 10.3) тот же самый запрос возвращает ошибку "Код состояния: 400 (Bad Request)".

В данной статье мы подробно разберем причины возникновения этой ошибки, выясним, как протоколы шифрования влияют на результат, и рассмотрим два способа решения проблемы: от настройки платформенных свойств до использования системных компонентов Windows.

Анализ исходной ситуации

Рассмотрим стандартный механизм отправки запроса, который может давать сбой в толстом клиенте. Проблема обычно проявляется при попытке авторизации, когда необходимо передать логин и пароль в формате JSON и получить токен доступа. Рассмотрим типичный код, который работает в современных условиях, но выдает ошибку в устаревших режимах совместимости:


Функция ПолучитьТокен()
    Логин = "**********";
    Пароль = "**********";
    ssl1 = Новый ЗащищенноеСоединениеOpenSSL;
    HTTPСоединение = Новый HTTPСоединение("sintec.club", 11000, , , , 60, ssl1);
    
    Данные = Новый Структура;
    Данные.Вставить("login", Логин);
    Данные.Вставить("password", Пароль);
    
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, Данные);
    ТелоЗапроса = ЗаписьJSON.Закрыть();
    
    АдресРесурса = "auth/sign-in";
    HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса);
    HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
    HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса);
    
    HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
    
    Если НЕ HTTPОтвет.КодСостояния = 200 Тогда
        Сообщить("Ошибка: " + HTTPОтвет.КодСостояния);
        Возврат Неопределено;
    КонецЕсли;
    
    // Обработка ответа...
КонецФункции

При запуске этого кода в конфигурации с низким режимом совместимости (например, 8.2.13), сервер возвращает код 400. Это происходит несмотря на то, что сама платформа 1С может быть версии 8.3.20 и выше. Причина кроется в том, как 1С обрабатывает защищенные соединения в режиме совместимости.

Причина №1: Поддержка протоколов TLS

Главная причина «необъяснимого» поведения кроется в протоколе TLS (Transport Layer Security). Современные веб-серверы из соображений безопасности отключают поддержку старых протоколов SSL 3.0, TLS 1.0 и TLS 1.1, требуя использования TLS 1.2 или выше.

Проанализируем работу платформы: поддержка протокола TLS 1.2 в 1С:Предприятие появилась начиная с версии 8.3.9. Если в вашей конфигурации установлен режим совместимости "8.2.13" или любой другой ниже "8.3.9", платформа ограничивает возможности объекта ЗащищенноеСоединениеOpenSSL. В результате попытка установить соединение происходит по устаревшему протоколу, который сервер отклоняет, возвращая ошибку 400 или просто обрывая сессию.

Решение 1: Изменение режима совместимости

Это самый правильный и «чистый» способ с точки зрения разработки на 1С. Посмотрим, как это реализовать:

  1. Откройте конфигуратор вашей базы.
  2. В дереве метаданных нажмите правой кнопкой мыши на корень (название конфигурации) и выберите "Свойства".
  3. Найдите свойство "Режим совместимости".
  4. Установите значение "Версия 8.3.9" (или выше, в зависимости от ваших задач).
  5. Примените изменения (F7).

Важное замечание: Смена режима совместимости — ответственный шаг. Это может повлечь за собой изменение поведения других функций, появление ошибок в типовом коде (например, в УТ 10.3 могут "поплыть" некоторые экранные формы или методы работы с файлами). После смены режима необходимо провести тщательное тестирование всей системы.

Рассмотрим, как изменится работа после обновления режима. Платформа начнет корректно использовать современные библиотеки OpenSSL, и ваш запрос к ресурсу auth/sign-in отработает успешно, вернув заветный код 200 или 201.

Решение 2: Использование WinHTTP (Обходной путь)

Если вы не можете изменить режим совместимости (например, из-за огромного количества доработок, которые ломаются при переходе), можно воспользоваться системным объектом Windows — WinHttp.WinHttpRequest.5.1. Этот объект работает в обход стандартных ограничений платформы 1С и использует настройки операционной системы.

Разберем пример кода с использованием этого метода:


Процедура ПолучитьТокенЧерезWinHTTP()
    Попытка
        WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
        
        // Настройка параметров соединения
        URL = "https://sintec.club:11000/auth/sign-in";
        WinHttp.Open("POST", URL, Ложь); // Ложь - синхронный запрос
        
        // Установка заголовков
        WinHttp.SetRequestHeader("Content-Type", "application/json; charset=utf-8");
        
        // Формирование тела запроса
        Данные = Новый Структура("login, password", "Логин", "Пароль");
        ЗаписьJSON = Новый ЗаписьJSON;
        ЗаписьJSON.УстановитьСтроку();
        ЗаписатьJSON(ЗаписьJSON, Данные);
        ТелоЗапроса = ЗаписьJSON.Закрыть();
        
        // Отправка
        WinHttp.Send(ТелоЗапроса);
        
        Если WinHttp.Status = 200 Тогда
            ОтветТекст = WinHttp.ResponseText;
            Сообщить("Токен получен!");
        Иначе
            Сообщить("Ошибка WinHTTP: " + WinHttp.Status + " " + WinHttp.ResponseText);
        КонецЕсли;
        
    Исключение
        Сообщить("Произошла критическая ошибка: " + ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

В некоторых случаях WinHTTP также может потребовать настройки параметров безопасности (например, если на сервере используется самоподписанный сертификат). Для этого используются специальные флаги (Option 4). Например, значение 13056 позволяет игнорировать большинство ошибок сертификатов, что бывает полезно при отладке в закрытых контурах.

Дополнительные нюансы: BOM и SNI

Выясним, какие еще факторы могут вызывать ошибку 400 в толстом клиенте:

  1. Метка BOM (Byte Order Mark): При использовании метода УстановитьТелоИзСтроки() в старых версиях 1С в начало строки может добавляться невидимый префикс BOM. Многие современные API (особенно написанные на Go или Node.js) воспринимают этот префикс как синтаксическую ошибку и возвращают 400. Чтобы этого избежать, можно формировать тело запроса как ДвоичныеДанные.
  2. SNI (Server Name Indication): Если целевой сервер использует виртуальные хосты (несколько сайтов на одном IP), старая версия платформы может не передавать имя сервера на этапе рукопожатия TLS. Это лечится опять же повышением режима совместимости до 8.3.12+.
  3. Content-Length: В толстом клиенте на старых режимах иногда некорректно вычисляется длина контента, если в JSON есть кириллица. Платформа может посчитать длину в символах, а сервер ожидает в байтах (UTF-8). Это приводит к «обрезанию» JSON-пакета.

Резюме

Если вы столкнулись с ошибкой 400 при POST-запросе в старой конфигурации, первым делом проверьте режим совместимости. В большинстве случаев переход на версию 8.3.9 решает проблему с TLS-соединением. Если же архитектура системы не позволяет менять режим совместимости, используйте WinHttp.WinHttpRequest.5.1, который позволит гибко управлять параметрами HTTPS-запроса на уровне операционной системы.

← На главную