Как передать тело в GET-запросе в 1С: решение проблемы

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

В современной разработке при интеграции 1С с внешними сервисами (такими как Wildberries API, ElasticSearch или Amazon S3) программисты часто сталкиваются с нестандартным требованием: передать данные в формате JSON внутри тела GET-запроса. В процессе отладки таких интеграций часто требуется предварительное тестирование запросов с сохранением всех параметров. Несмотря на то что технически протокол HTTP это допускает, встроенные средства платформы 1С:Предприятие имеют жесткие ограничения на этот счет. В данной статье мы подробно разберем, почему возникает ошибка "request body has an error", и рассмотрим все рабочие способы обхода этого ограничения.

Проанализируем причину проблемы: почему 1С блокирует тело GET-запроса?

Начиная с версий платформы 8.3.14 и выше (особенно заметно в 8.3.17+), разработчики 1С привели работу встроенного объекта HTTPСоединение в строгое соответствие со стандартами RFC. Согласно семантике протокола HTTP, метод GET предназначен исключительно для получения информации, и наличие тела в нем не имеет определенного значения для сервера.

Если мы попытаемся выполнить следующий привычный код:


Запрос = Новый HTTPЗапрос(АдресРесурса, Заголовки);      
Запрос.УстановитьТелоИзСтроки(JsonСтрока);
Ответ = Соединение.Получить(Запрос);

Платформа при вызове метода Получить() или ВызватьHTTPМетод("GET") просто проигнорирует содержимое, установленное через УстановитьТелоИзСтроки(). Перед отправкой стоит убедиться, что все обязательные поля в строке JSON заполнены, чтобы исключить ошибки на стороне логики. В результате на сервер придет «пустой» запрос, и вы получите ошибку от API, например: {"errors":["request body has an error: value is required but missing"]}. Это поведение официально зафиксировано в документации к платформе: "При использовании метода GET тело запроса на сервер отправлено не будет".

Выясним, как мы можем обойти это поведение, используя альтернативные инструменты.

Решение 1: Использование COM-объекта WinHttp.WinHttpRequest (для Windows)

Самым стабильным и эффективным решением для серверов под управлением Windows является использование объекта WinHttp.WinHttpRequest.5.1. Этот объект работает напрямую с системными библиотеками Windows и не накладывает искусственных ограничений на структуру запроса. Рассмотрим реализацию по шагам:

  1. Создаем экземпляр COM-объекта.
  2. Инициализируем соединение методом Open.
  3. Устанавливаем необходимые заголовки (авторизация, тип контента). Для сложных сценариев безопасности, например, когда нужна подпись RSA с хешированием SHA512 для получения токена, заголовки формируются заранее.
  4. Отправляем запрос, передав строку JSON непосредственно в метод Send.

Пример кода для реализации этого метода:


// Подготовим данные
АдресРесурса = "https://statistics-api.wildberries.ru/api/v1/delayed-gen/tasks";
ТелоЗапроса = "{""ids"": [""497f6eca-6276-4993-bfeb-53cbbbba6f08""]}";

// Создаем объект
WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");

// Открываем соединение (метод GET, URL, асинхронность = Ложь)
WinHttp.Open("GET", АдресРесурса, Ложь);

// Устанавливаем заголовки
WinHttp.SetRequestHeader("Content-Type", "application/json");
WinHttp.SetRequestHeader("Authorization", ТокенАвторизации);

// Отправляем тело
Попытка
    WinHttp.Send(ТелоЗапроса);
    КодСостояния = WinHttp.Status;
    ТекстОтвета = WinHttp.ResponseText;
    Сообщить("Ответ сервера (" + КодСостояния + "): " + ТекстОтвета);
Исключение
    Сообщить("Ошибка при отправке запроса: " + ОписаниеОшибки());
КонецПопытки;

Важный нюанс: Этот метод будет работать только на стороне сервера (или клиента), работающего под Windows. Если ваша база развернута на Linux, этот вариант не подойдет.

Решение 2: Использование утилиты cURL (универсальный способ)

Если ваш сервер работает на ОС Linux или вы хотите иметь кроссплатформенное решение, разберем вариант с использованием системной утилиты curl. Она позволяет гибко настраивать параметры запроса, что часто применяется, когда реализуется надежная выгрузка в Google Таблицы через сервисный аккаунт, где важна стабильность передачи данных.

Проанализируем пример формирования команды для запуска:


// Формируем строку JSON и записываем ее во временный файл (чтобы избежать проблем с кавычками в командной строке)
ИмяФайлаТела = ПолучитьИмяВременногоФайла("json");
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.УстановитьТекст(JsonСтрока);
ТекстовыйДокумент.Записать(ИмяФайлаТела, КодировкаТекста.UTF8);

ИмяФайлаОтвета = ПолучитьИмяВременногоФайла("txt");

// Собираем команду cURL
// -X GET: принудительно устанавливаем метод
// -H: заголовки
// -d @путь: передаем тело из файла
Команда = "curl -X GET """ + АдресРесурса + """ "
        + "-H ""Authorization: " + Токен + """ "
        + "-H ""Content-Type: application/json"" "
        + "-d @""" + ИмяФайлаТела + """ "
        + "-o """ + ИмяФайлаОтвета + """";

// Запускаем приложение
ЗапуститьПриложение(Команда, , Истина); // Ждем завершения

// Читаем результат
ТекстОтвета = Новый ТекстовыйДокумент;
ТекстОтвета.Прочитать(ИмяФайлаОтвета, КодировкаТекста.UTF8);
Результат = ТекстОтвета.ПолучитьТекст();

// Удаляем временные файлы
УдалитьФайлы(ИмяФайлаТела);
УдалитьФайлы(ИмяФайлаОтвета);

Этот способ является наиболее мощным, так как curl поддерживает огромное количество протоколов и настроек прокси, которые в 1С реализовать бывает затруднительно.

Решение 3: Использование MSXML2.ServerXMLHTTP

Разберем еще один вариант с использованием библиотеки MSXML. Объект MSXML2.ServerXMLHTTP часто считается более предпочтительным для серверного кода 1С, так как он оптимизирован для многопоточной работы. В некоторых случаях для реализации специфической логики или обхода ограничений разработчики даже используют COM-объекты, созданные на языке Python, чтобы расширить стандартный функционал 1С.


HTTP = Новый COMОбъект("MSXML2.ServerXMLHTTP");
HTTP.Open("GET", URL, Ложь);
HTTP.SetRequestHeader("Content-Type", "application/json");
HTTP.Send(ТелоJSON);

Если HTTP.Status = 200 Тогда
    Сообщить(HTTP.ResponseText);
КонецЕсли;

Как и в случае с WinHttpRequest, этот объект игнорирует ограничения 1С и передает данные в потоке вывода (output stream) даже для GET-запроса.

Альтернативные подходы и "подводные камни"

Рассмотрим ситуацию, когда ни один из вышеперечисленных методов не помогает. Бывают случаи, когда даже если 1С отправит тело, оно «отрезается» промежуточным прокси-сервером или балансировщиком нагрузки. В такой ситуации проанализируем следующие варианты:

Резюме: Если вы столкнулись с необходимостью отправить тело в GET-запросе, не пытайтесь заставить работать стандартный объект HTTPСоединение. Используйте WinHttp.WinHttpRequest для Windows-серверов или вызов curl для универсальных решений. Это сэкономит время и обеспечит корректную работу интеграции с современными внешними сервисами.

← На главную