В процессе интеграции 1С с современными веб-сервисами разработчики периодически сталкиваются с нестандартными требованиями API сторонних систем. Одно из таких требований — передача параметров в формате JSON непосредственно в теле (Request Body) HTTP-запроса с методом GET. Классический пример — популярный поисковый движок Elasticsearch или специфические методы авторизации и получения статусов документов в коммерческих API.
При попытке реализовать подобный запрос стандартными средствами 1С разработчики неизбежно сталкиваются с ошибками сервера вроде "пустая строка JSON" или ошибками парсинга. В этой статье мы подробно разберем, почему возникает эта проблема, как ведет себя платформа 1С и какими способами можно обойти данное ограничение.
Давайте обратимся к теории веб-протоколов и логике платформы «1С:Предприятие». Согласно спецификации HTTP, метод GET предназначен для получения информации с сервера, и передача параметров традиционно должна происходить через строку запроса (URL Query Parameters). Хотя современные стандарты (в частности, RFC 9110) допускают наличие тела в GET-запросах при предварительной договоренности между клиентом и сервером, многие сетевые библиотеки и промежуточные узлы (прокси, фаерволы, балансировщики нагрузки) до сих пор принудительно отбрасывают тело таких запросов в целях безопасности.
Разработчики платформы 1С приняли консервативное решение и заблокировали эту возможность на уровне кода. Если мы откроем Синтакс-Помощник к объекту HTTPСоединение и его методам Получить() или универсальному ВызватьHTTPМетод(), мы увидим официальное примечание:
«При использовании метода GET тело запроса на сервер отправлено не будет.»
Даже если мы попытаемся использовать объект HTTPЗапрос и применить к нему метод УстановитьТелоИзСтроки(), при выполнении метода GET платформа 1С принудительно очистит отправляемый буфер данных. Использование сторонних популярных библиотек-оберток (например, «Коннектор» для 1С) также не принесет результата, поскольку под капотом они используют все те же стандартные платформенные объекты.
Тем не менее, если стороннее API жестко требует именно GET с телом, и у нас нет возможности повлиять на разработчиков этого API, проблему приходится решать обходными путями. Рассмотрим три рабочих сценария решения этой задачи.
Консольная утилита curl является стандартом де-факто для работы с сетевыми запросами в операционных системах Linux и современных версиях Windows 10/11 / Windows Server. Данная утилита умеет принудительно отправлять тело с любым HTTP-методом.
Рассмотрим алгоритм реализации этого подхода в коде 1С по шагам:
curl, где указываем принудительный метод -X GET, путь к файлу с телом через параметр -d @ и файл для сохранения ответа сервера через -o.ЗапуститьПриложение() в синхронном режиме.Ниже представлен готовый пример кода, реализующий данный алгоритм:
// Шаг 1. Формируем JSON-структуру запроса
СтруктураДанных = Новый Структура;
СтруктураДанных.Вставить("Id", "123456789");
СтруктураДанных.Вставить("Id_doc", "555");
ЗаписьJSON = Новый ЗаписьJSON;
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(,,, ЭАП_Токен); // Если нужна спец-кодировка
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписи);
ЗаписатьJSON(ЗаписьJSON, СтруктураДанных);
СтрокаJSON = ЗаписьJSON.Закрыть();
// Шаг 2. Создаем временные файлы
ИмяФайлаЗапроса = ПолучитьИмяВременногоФайла("json");
ИмяФайлаОтвета = ПолучитьИмяВременногоФайла("json");
// Записываем JSON во временный файл в кодировке UTF-8 без BOM
ЗаписьТекста = Новый ЗаписьТекста(ИмяФайлаЗапроса, КодировкаТекста.UTF8, СимволыВСтроке.Нет, Ложь);
ЗаписьТекста.Записать(СтрокаJSON);
ЗаписьТекста.Закрыть();
// Шаг 3. Сборка команды для curl
// Флаг -s отключает индикатор прогресса curl в консоли
URLПодключения = "https://your-api-domain.com/api/getStatus";
СтрокаКоманды = "curl -s -X GET """ + URLПодключения + """ "
+ "-H ""Content-Type: application/json"" "
+ "-d @" + """" + ИмяФайлаЗапроса + """ "
+ "-o " + """" + ИмяФайлаОтвета + """";
// Шаг 4. Запуск утилиты в режиме ожидания завершения
КодВозврата = Неопределено;
ЗапуститьПриложение(СтрокаКоманды,, Истина, КодВозврата);
// Шаг 5. Обработка результатов
Если КодВозврата = 0 Тогда
ЧтениеТекста = Новый ЧтениеТекста(ИмяФайлаОтвета, КодировкаТекста.UTF8);
СтрокаОтвета = ЧтениеТекста.Прочитать();
ЧтениеТекста.Закрыть();
// Выводим полученный ответ сервера
Сообщить(СтрокаОтвета);
Иначе
ВызватьИсключение "Ошибка при выполнении запроса через curl. Код возврата: " + КодВозврата;
КонецЕсли;
// Очистка временных файлов
УдалитьФайлы(ИмяФайлаЗапроса);
УдалитьФайлы(ИмяФайлаОтвета);
Этот способ является наиболее надежным, так как работает одинаково хорошо и на Windows-серверах, и на серверах под управлением Linux.
На форумах часто советуют использовать стандартный системный Windows-компонент WinHttp.WinHttpRequest.5.1. Однако будьте осторожны: библиотека WinHTTP на уровне операционной системы Microsoft Windows ведет себя аналогично платформе 1С — она автоматически очищает тело запроса, если в методе open() указан верб "GET".
Чтобы обойти это системное ограничение в среде Windows, мы можем использовать другой COM-объект — MSXML2.ServerXMLHTTP.6.0. Этот компонент более лоялен к стандартам и позволяет передать строку с телом в метод send() даже при использовании GET-запроса.
Проанализируем пример кода с использованием этого объекта:
// Способ работает только в среде ОС Windows
#Если Клиент Или НаСервере Тогда
Если Найти(ВРег(СистемнаяИнформация.ОперационнаяСистема), "WINDOWS") > 0 Тогда
URL = "https://your-api-domain.com/api/getStatus";
СтрокаJSON = "[{""Id"": ""123456789"", ""Id_doc"": ""555""}]";
Попытка
HttpReq = Новый COMОбъект("MSXML2.ServerXMLHTTP.6.0");
HttpReq.open("GET", URL, Ложь); // Ложь — для синхронного выполнения
HttpReq.setRequestHeader("Content-Type", "application/json");
HttpReq.setRequestHeader("Accept", "application/json");
// Отправляем запрос, передавая JSON непосредственно в параметры метода send
HttpReq.send(СтрокаJSON);
Если HttpReq.status = 200 Тогда
СтрокаОтвета = HttpReq.responseText;
Сообщить("Ответ сервера: " + СтрокаОтвета);
Иначе
Сообщить("Ошибка сервера: " + HttpReq.status + " " + HttpReq.statusText);
КонецЕсли;
Исключение
Сообщить("Не удалось выполнить запрос через MSXML2.ServerXMLHTTP: " + ОписаниеОшибки());
КонецПопытки;
Иначе
Сообщить("Данный способ доступен только для операционной системы Windows!");
КонецЕсли;
#КонецЕсли
Главный плюс этого варианта — отсутствие необходимости сохранять промежуточные файлы на диск и вызывать внешние процессы, что положительно сказывается на производительности интеграции.
Если запросы к API выполняются интенсивно (десятки тысяч запросов в час), постоянный вызов внешней утилиты curl через операционную систему может создавать избыточную нагрузку на процессор сервера 1С. В таком случае идеальным архитектурным решением станет создание небольшого промежуточного прокси-скрипта (веб-хука) на вашем веб-сервере.
Скрипт пишется буквально в несколько строк на любом удобном языке программирования (PHP, Python, Node.js). Схема работы выглядит следующим образом:
POST-запрос, в тело которого помещает целевой JSON и адрес внешнего API.POST-запрос, извлекает тело и адрес назначения.requests на Python или cURL на PHP) выполняет реальный GET-запрос к внешнему API.POST-запрос.Такой подход полностью решает проблему производительности и избавляет код 1С от зависимости от системных утилит или COM-объектов операционной системы, сохраняя код конфигурации чистым и кроссплатформенным.