При интеграции 1С со сторонними сервисами (REST API) программисты часто сталкиваются с задачей: необходимо отправить структуру данных в формате RAW JSON в теле POST-запроса. Бывает так, что в сторонних инструментах, таких как Postman, запрос отрабатывает корректно, а из 1С сервер возвращает ошибку (например, 400 Bad Request: operation not specified). Рассмотрим подробнее, почему так происходит и как правильно формировать и отправлять такие запросы.
Одна из самых частых ошибок при формировании JSON для внешних систем — использование платформенного сериализатора XDTO. В исходном коде разработчик попытался перевести данные в JSON следующим образом:
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
СериализаторXDTO.ЗаписатьJSON(ЗаписьJSON, ДанныеPOST, НазначениеТипаXML.Явное);
РезультатСтрока = ЗаписьJSON.Закрыть();
Проанализируем ситуацию: СериализаторXDTO предназначен для обмена данными между базами 1С. При сериализации он добавляет в итоговую строку служебные метаданные типов (например, "#type": "jcfg:Structure"). Внешние системы не понимают эти специфичные дополнения и отклоняют запрос, так как получают невалидный, с их точки зрения, JSON.
Решение: Для формирования классического, чистого JSON стандарта RFC 4627 без "мусора" всегда используйте глобальный метод ЗаписатьJSON(). Перепишем этот фрагмент:
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ДанныеPOST); // Используем стандартный метод
РезультатСтрока = ЗаписьJSON.Закрыть();
В попытках передать RAW data разработчики часто пытаются вручную рассчитать размер передаваемых данных и указать заголовок Content-Length. Для этого иногда даже создают временные файлы. Это лишняя работа и антипаттерн в 1С. Посмотрим на пример кода, который лучше не использовать:
// Лишний код: ручной расчет длины
ФайлОтправки = Новый Файл(ИмяФайлаОтправки);
РазмерФайлаОтправки = XMLСтрока(ФайлОтправки.Размер());
ЗаголовкиHTTP.Вставить("Content-Length", РазмерФайлаОтправки);
Платформа 1С самостоятельно и абсолютно точно рассчитывает и подставляет заголовок Content-Length в байтах при вызове методов отправки HTTP-запроса. Если вы посчитаете длину строки программно (в символах, а не в байтах), и там окажутся кириллические символы, ваш Content-Length не совпадет с реальностью, и сервер выдаст ошибку.
Передавая тело запроса из строки, необходимо правильно указать кодировку. Часто разработчики пишут так:
HTTPЗапрос.УстановитьТелоИзСтроки(РезультатСтрока, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.Использовать);
Большинство современных REST API строго ожидают кодировку UTF-8 без спецификации (BOM). Включение BOM добавляет в начало потока три невидимых байта. Из-за этого парсер на стороне сервера может "сломаться" и не распознать структуру JSON. Всегда используйте ИспользованиеByteOrderMark.НеИспользовать.
Для генерации JSON-объектов в 1С обычно используют тип данных Структура. Но у нее есть ограничение: ключи структуры должны соответствовать правилам именования переменных 1С (они не могут начинаться с цифры, содержать дефисы или пробелы).
Выясним, что делать, если внешнее API требует передать ключ вида "1st-param" или "my key". В этом случае вместо структуры необходимо использовать тип Соответствие. Метод ЗаписатьJSON() обработает его аналогично структуре, сформировав правильный JSON-объект с любыми строковыми ключами.
Для отправки POST-запросов используется метод соединения ОтправитьДляОбработки(). Однако, если документация стороннего сервиса требует отправки RAW data методами PUT, PATCH или DELETE, используйте универсальный метод:
РезультатЗапроса = Соединение.ВызватьHTTPМетод("PUT", HTTPЗапрос);
Если сервер возвращает ошибку (например, статус 400) и передает пояснение в формате JSON, получить этот текст для анализа можно так:
СтрокаОтвета = РезультатЗапроса.ПолучитьТелоКакСтроку();
Соберем все рекомендации вместе и сформируем правильный алгоритм отправки RAW JSON:
АдресРесурса = "/api/endpoint";
Соединение = Новый HTTPСоединение("api.example.com", 443,,,,, Новый ЗащищенноеСоединениеOpenSSL());
ЗаголовкиHTTP = Новый Соответствие;
ЗаголовкиHTTP.Вставить("Content-Type", "application/json");
ЗаголовкиHTTP.Вставить("Accept", "application/json");
ЗаголовкиHTTP.Вставить("Authorization", "Bearer " + Токен);
// Content-Length 1С добавит автоматически
HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса, ЗаголовкиHTTP);
// Формируем данные
ДанныеPOST = Новый Структура;
ДанныеPOST.Вставить("param1", "0");
ДанныеPOST.Вставить("param2", Истина);
ДанныеPOST.Вставить("param3", "A");
ДанныеТовары = Новый Структура;
ДанныеТовары.Вставить("param1_1", 0);
ДанныеТовары.Вставить("param1_2", "t");
М = Новый Массив;
М.Добавить(ДанныеТовары);
ДанныеPOST.Вставить("params", М);
// Правильно переводим в JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ДанныеPOST); // Без сериализатора XDTO
РезультатСтрока = ЗаписьJSON.Закрыть();
// Передаем строку в тело без BOM
HTTPЗапрос.УстановитьТелоИзСтроки(РезультатСтрока, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
// Отправляем POST запрос
РезультатЗапроса = Соединение.ОтправитьДляОбработки(HTTPЗапрос);
// Читаем ответ
КодСостояния = РезультатЗапроса.КодСостояния;
СтрокаОтвета = РезультатЗапроса.ПолучитьТелоКакСтроку();
Если КодСостояния = 200 Тогда
Сообщить("Успешно!");
Иначе
Сообщить("Ошибка: " + СтрокаОтвета);
КонецЕсли;
Следуя этим простым правилам (использование глобального метода записи JSON, отказ от ручного подсчета длины, выключение маркера BOM и грамотный выбор типов коллекций), вы сможете успешно интегрировать 1С с любыми современными веб-сервисами, принимающими данные в формате RAW JSON.