При интеграции 1С со сторонними веб-сервисами (например, Zabbix API или другими службами на базе JSON-RPC) разработчики часто сталкиваются с ситуацией, когда проверенный через утилиту cURL или Postman запрос успешно выполняется, а аналогичный вызов из встроенного языка 1С возвращает пустой ответ или завершается с ошибкой. Разберем по шагам, почему так происходит, какие скрытые нюансы существуют при работе с объектами HTTPСоединение и HTTPЗапрос, и как правильно реализовать обмен.
Рассмотрим типовой сценарий: необходимо отправить POST-запрос с JSON-телом на веб-сервер. В процессе реализации часто допускаются неочевидные ошибки, которые приводят к искажению пакета данных:
ЗаголовокЗапросаHTTP.Вставить("Content-Type: ", "application/json-rpc"), платформа 1С при формировании сетевого заголовка автоматически добавит разделительное двоеточие. На веб-сервер уйдет заголовок Content-Type: : application/json-rpc. Многие парсеры и веб-серверы отбрасывают такие заголовки, не понимая формат переданных данных. Имя заголовка в ключе соответствия должно быть строго без двоеточия и пробелов — "Content-Type".HTTPЗапрос.УстановитьТелоИзСтроки() по умолчанию может добавлять в начало потока байты BOM (Byte Order Mark). Многие веб-серверы и функции разбора JSON (например, стандартный json_decode в PHP) не могут обработать строку с BOM и признают JSON невалидным, возвращая ошибку 400 или пустой ответ.ТекстовыйДокумент усложняет код и маскирует реальный код состояния HTTP-ответа.Выясним причину проблем и перепишем код, исключив лишние дисковые операции. Объект HTTPОтвет, возвращаемый методами объекта HTTPСоединение, позволяет получить тело ответа напрямую в переменную типа Строка с помощью метода ПолучитьТелоКакСтроку(), а также проверить свойство КодСостояния.
Посмотрим на пример правильной отправки запроса с контролем заголовков и отключением BOM:
СерверПриемник = "zbx.ru";
АдресСтраницыНаСервере = "/api_jsonrpc.php"; // Рекомендуется указывать ведущий слэш
Таймаут = 120;
// Инициализируем соединение без указания протокола в имени сервера
HTTP = Новый HTTPСоединение(СерверПриемник, , , , , Таймаут);
// Формируем заголовки: имя заголовка указывается строго без двоеточия
Заголовки = Новый Соответствие();
Заголовки.Вставить("Content-Type", "application/json-rpc");
HTTPЗапрос = Новый HTTPЗапрос(АдресСтраницыНаСервере, Заголовки);
// Формируем тело JSON без лишних обрамляющих скобок
СтрокаJSON = "{
| ""jsonrpc"": ""2.0"",
| ""method"": ""host.get"",
| ""params"": {""groupids"": ""45""},
| ""id"": 0,
| ""auth"": ""9a59f9d85ba01c2036bc59932a""
|}";
// Обязательно указываем кодировку UTF-8 и отключаем использование Byte Order Mark (BOM)
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
// Отправляем запрос и получаем ответ в память без промежуточных файлов
Ответ = HTTP.ОтправитьДляОбработки(HTTPЗапрос);
// Проверяем результат выполнения
Если Ответ.КодСостояния = 200 Тогда
СтрокаОтвета = Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
Сообщить(СтрокаОтвета);
Иначе
Сообщить("Ошибка вызова сервиса. Код состояния: " + Ответ.КодСостояния);
Сообщить("Тело ответа: " + Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8));
КонецЕсли;
Рассмотрим подробнее альтернативный и более надежный подход. Чтобы избежать ошибок форматирования кавычек, спецсимволов и управляющих конструкций в JSON-строках, рекомендуется формировать структуру данных во встроенном языке 1С и выполнять ее сериализацию при помощи объектов ЗаписьJSON и ЗаписатьJSON.
Разберем этот вариант по шагам:
// Шаг 1. Формируем структуру параметров запроса
ПараметрыЗапроса = Новый Структура();
ПараметрыЗапроса.Вставить("groupids", "45");
ТелоСтруктура = Новый Структура();
ТелоСтруктура.Вставить("jsonrpc", "2.0");
ТелоСтруктура.Вставить("method", "host.get");
ТелоСтруктура.Вставить("params", ПараметрыЗапроса);
ТелоСтруктура.Вставить("id", 0);
ТелоСтруктура.Вставить("auth", "9a59f9d85ba01c2036bc59932a");
// Шаг 2. Сериализуем структуру в JSON-строку
ЗаписьJSON = Новый ЗаписьJSON();
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет);
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписи);
ЗаписатьJSON(ЗаписьJSON, ТелоСтруктура);
СтрокаJSON = ЗаписьJSON.Закрыть();
// Шаг 3. Отправляем сформированные данные на сервер
HTTP = Новый HTTPСоединение("zbx.ru", , , , , 120);
Заголовки = Новый Соответствие();
Заголовки.Вставить("Content-Type", "application/json-rpc");
HTTPЗапрос = Новый HTTPЗапрос("/api_jsonrpc.php", Заголовки);
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Ответ = HTTP.ОтправитьДляОбработки(HTTPЗапрос);
Если Ответ.КодСостояния = 200 Тогда
СтрокаОтвета = Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
// Шаг 4. Читаем ответ сервера в структуру
ЧтениеJSON = Новый ЧтениеJSON();
ЧтениеJSON.УстановитьСтроку(СтрокаОтвета);
ДанныеОтвета = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
// Теперь с результатом можно работать как с объектом Соответствие или Структура
Иначе
ВызватьИсключение "Ошибка HTTP: " + Ответ.КодСостояния;
КонецЕсли;
HTTPСоединение указывается только доменное имя или IP-адрес (например, "zbx.ru"). Указание префикса протокола вида "http://" является ошибкой и приводит к невозможности разрешения сетевого адреса.HTTPСоединение необходимо передать порт 443 и объект ЗащищенноеСоединениеOpenSSL.Ответ.КодСостояния.