При интеграции 1С с внешними веб-сервисами и API разработчики нередко сталкиваются с ситуацией, когда отправленный корректный JSON-документ не принимается сервером. В ответ API возвращает ошибку разбора, например, «Unable to parse JSON request» или «Invalid JSON». При этом локальная проверка текста в редакторах показывает валидную структуру, а аналогичный запрос из другой конфигурации или через сторонние утилиты может выполняться успешно. Разберем по шагам, почему возникает эта проблема и как правильно настроить передачу данных в 1С.
Проанализируем ситуацию и выясним, почему принимающий веб-сервер не может обработать сформированный запрос:
EF BB BF в начале потока UTF-8). Большинство современных серверных библиотек парсинга строго придерживаются стандарта и аварийно завершают обработку, встретив невидимые служебные байты перед первой открывающей скобкой { или [.УстановитьТелоИзСтроки объекта HTTPЗапрос без явного указания режима BOM платформа может автоматически добавлять сигнатуру байтов к строке в кодировке UTF-8.application/json; charset=utf-8, веб-сервер может попытаться интерпретировать UTF-8 в другой кодировке (например, Windows-1251 или ISO-8859-1), что при наличии кириллицы приведет к искажению синтаксиса.Рассмотрим основной и самый правильный способ решения проблемы штатными средствами 1С:Предприятие. При формировании тела HTTPЗапрос необходимо явно передать третий параметр — значение перечисления ИспользованиеByteOrderMark.НеИспользовать.
Посмотрим на пример правильной инициализации запроса:
// Формируем JSON-строку
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();
ЗаписатьJSON(Запись, СтруктураДанных);
СтрокаJSON = Запись.Закрыть();
// Формируем HTTP-запрос с отключением BOM
Запрос = Новый HTTPЗапрос(URIСтрока);
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Запрос.УстановитьТелоИзСтроки(СтрокаJSON, "UTF-8", ИспользованиеByteOrderMark.НеИспользовать);
// Выполняем отправку
Ответ = HTTPСоединение.ОтправитьДляОбработки(Запрос);
В более старых релизах платформы или специфических режимах совместимости иногда применялся хак с указанием кодировки "CESU-8", которая подавляла вставку BOM. Однако в современном коде рекомендуется всегда использовать стандартный UTF-8 совместно с ИспользованиеByteOrderMark.НеИспользовать.
Если мы хотим полностью контролировать побайтовое содержимое тела запроса и исключить влияние внутренних механизмов работы HTTPЗапрос со строками, воспользуемся явной конвертацией в двоичные данные. Разберем этот вариант:
// Преобразуем строку в двоичные данные без добавления BOM (третий параметр - Ложь)
ДвоичныеДанныеТела = ПолучитьДвоичныеДанныеИзСтроки(СтрокаJSON, КодировкаТекста.UTF8, Ложь);
// Устанавливаем двоичные данные в запрос
Запрос = Новый HTTPЗапрос(URIСтрока);
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Запрос.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеТела);
Ответ = HTTPСоединение.ОтправитьДляОбработки(Запрос);
Такой подход гарантирует, что в поток отправки попадут исключительно байты текста JSON без каких-либо служебных префиксов.
Некоторые внешние API чувствительны не только к BOM, но и к форматированию пробелов, переносов строк или экранированию спецсимволов. Рассмотрим, как настроить сериализатор ЗаписьJSON для получения компактной и строгой строки:
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(
ПереносСтрокJSON.Нет, // Отключаем лишние переносы строк
" ", // Символ отступа
Истина, // Экранировать специальные символы
ЭкранированиеСимволовJSON.СимволыВнеASCII // Корректная обработка национальных символов
);
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку(ПараметрыЗаписи);
ЗаписатьJSON(Запись, СтруктураДанных);
СтрокаJSON = Запись.Закрыть();
Использование явных параметров форматирования предотвращает искажение служебных символов внутри строковых значений (например, в паролях, логинах и токенах авторизации).
В конфигурациях на обычных формах (например, в УПП 1.3), где могут действовать ограничения старых версий платформы, альтернативным вариантом является отправка запроса через системный COM-объект операционной системы. Разберем пример реализации:
HTTP = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
HTTP.Open("POST", АдресСервиса, Ложь);
HTTP.SetRequestHeader("Content-Type", "application/json; charset=utf-8");
// Отправляем тело запроса напрямую
HTTP.Send(СтрокаJSON);
КодСостояния = HTTP.Status;
ТекстОтвета = HTTP.ResponseText;
Объект WinHttp.WinHttpRequest.5.1 передает строку напрямую в системный стек Windows без автоматического добавления UTF-8 BOM, что решает проблему совместимости с внешними веб-серверами.