Как исправить ошибку "Unexpected character encountered while parsing value" при отправке JSON в 1С?

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

При интеграции 1С со сторонними веб-сервисами (особенно написанными на стеке .NET) разработчики часто сталкиваются с ситуацией, когда корректно сформированный POST-запрос с телом в формате JSON отклоняется сервером. В ответ возвращается статус 400 (Bad Request) и сообщение об ошибке валидации.

Рассмотрим типичную ситуацию. Изначально стоит задача переписать следующий curl-запрос на язык 1С:


curl -X POST "https://api-сервер/api/Search/SearchCompany?apiVersion=1.3" \
-H "accept: text/plain" \
-H "accessKey: ВАШ_КЛЮЧ" \
-H "Content-Type: application/json-patch+json" \
-d "{ \"language\": \"Russian\", \"searchCompanyParameters\": { \"taxNumber\": \"261220411395\" } }"

Разберем базовый вариант кода в 1С, который часто пишут разработчики для решения этой задачи:


Процедура ОтправитьHTTPЗапрос()
    
    СтрокаURI = "api-сервер/api/Search/SearchCompany?apiVersion=1.3";
    СтруктураURI = СтруктураURI(СтрокаURI); // Функция разбора URL
    
    HTTPСоединение = Новый HTTPСоединение(СтруктураURI.Хост, СтруктураURI.Порт,,,,,Новый ЗащищенноеСоединениеOpenSSL);
    
    Заголовки = Новый Соответствие;
    Заголовки.Вставить("accept","text/plain");
    Заголовки.Вставить("accessKey","ВАШ_КЛЮЧ");
    Заголовки.Вставить("Content-Type","application/json-patch+json");
    
    СтруктураДляJSON = Новый Структура("language","Russian");
    СтруктураДляJSON.Вставить("searchCompanyParameters", Новый Структура("taxNumber","261220411395"));
    
    Запись = Новый ЗаписьJSON;
    Запись.УстановитьСтроку();
    ЗаписатьJSON(Запись, СтруктураДляJSON);
    ТелоЗапроса = Запись.Закрыть();
    
    HTTPЗапрос = Новый HTTPЗапрос(СтруктураURI.ПутьНаСервере, Заголовки);
    HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса);
    
    HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
    СтрокаОтвета = HTTPОтвет.ПолучитьТелоКакСтроку();
    
КонецПроцедуры

При выполнении этого кода сервер возвращает ошибку:

{"errors":{"":["Unexpected character encountered while parsing value: . Path '', line 0, position 0."],"searchRequest":["The searchRequest field is required."]},"type":" validation errors occurred.","status":400}

Проанализируем эту ошибку. Перевод гласит: "При синтаксическом анализе значения обнаружен неожиданный символ". Если скопировать тело JSON и проверить его в любом онлайн-валидаторе, он покажет, что JSON абсолютно корректен. Так откуда берется ошибка? Выясним истинную причину.

Природа "невидимой" ошибки: маркер BOM

Символ, который в тексте ошибки выглядит как пустота или странная точка перед словом Path, — это BOM (Byte Order Mark, маркер последовательности байтов). В Юникоде он обозначается как \uFEFF.

Многие современные веб-сервисы строго следуют стандарту RFC 8259. Согласно этому стандарту, поток данных JSON не должен начинаться с маркера BOM. Если строгий парсер (например, Newtonsoft.Json) видит эти служебные байты в самом начале запроса, он спотыкается на нулевой позиции, так как ожидает увидеть открывающую фигурную скобку {, а не служебный символ.

Почему это происходит в 1С? Посмотрим на метод УстановитьТелоИзСтроки(). Если использовать его с параметрами по умолчанию:

HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса);

Платформа 1С (в зависимости от режима совместимости, обычно 8.3.5 и ниже) при формировании строки в кодировке UTF-8 принудительно добавляет BOM-маркер в начало строки. На некоторых компьютерах или при использовании корпоративных прокси-серверов этот символ может "срезаться" сетевым оборудованием (поэтому иногда код магическим образом начинает работать на другой машине), но полагаться на это нельзя.

Решение 1: Правильное использование метода УстановитьТелоИзСтроки (для современных платформ)

Чтобы код гарантированно работал на любой машине и при любых сетевых настройках, нам необходимо явно запретить платформе 1С добавлять маркер BOM при отправке запроса. Разберем по шагам, как это сделать.

Метод УстановитьТелоИзСтроки принимает дополнительные параметры кодировки и использования BOM. Запишем вызов метода правильно:


HTTPЗапрос = Новый HTTPЗапрос(СтруктураURI.ПутьНаСервере, Заголовки);

// Явно отключаем BOM третьим параметром:
HTTPЗапрос.УстановитьТелоИзСтроки(
    ТелоЗапроса, 
    КодировкаТекста.UTF8, 
    ИспользованиеByteOrderMark.НеИспользовать
);

HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);

Передав ИспользованиеByteOrderMark.НеИспользовать, мы гарантируем, что тело запроса начнется ровно со скобки {, и принимающий сервер успешно распарсит наш JSON.

Решение 2: Использование двоичных данных (универсальный метод для старых версий 1С)

Если вы работаете на устаревшей версии платформы 1С или находитесь в жестком режиме совместимости, где у метода УстановитьТелоИзСтроки недоступен параметр отключения BOM, мы можем обойти эту проблему, сформировав тело запроса через временный файл.

Рассмотрим этот алгоритм подробнее:

  1. Создаем временный файл.
  2. Записываем в него строку JSON с помощью объекта ЗаписьТекста, явно указав отсутствие BOM.
  3. Читаем файл как ДвоичныеДанные.
  4. Устанавливаем тело запроса из полученных двоичных данных.

Посмотрим на пример реализации:


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

// 5-й параметр в Ложь отключает добавление BOM при записи файла
ЗаписьТ = Новый ЗаписьТекста(ИмяВремФайла, КодировкаТекста.UTF8, , , Ложь);
ЗаписьТ.Записать(ТелоЗапроса);
ЗаписьТ.Закрыть();

// Читаем чистые байты без спецсимволов
ДвоичныеДанныеТела = Новый ДвоичныеДанные(ИмяВремФайла);

HTTPЗапрос = Новый HTTPЗапрос(СтруктураURI.ПутьНаСервере, Заголовки);
// Устанавливаем тело запроса из двоичных данных
HTTPЗапрос.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеТела);

HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);

// Не забываем удалить временный файл
УдалитьФайлы(ИмяВремФайла);

Решение 3: Альтернативная кодировка CESU-8

В качестве еще одного "хака" для старых платформ можно рассмотреть передачу другой кодировки. Если вместо стандартного UTF-8 указать кодировку CESU-8, платформа 1С сформирует корректный текстовый поток без добавления маркера BOM.

HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса, "CESU-8");

Однако этот способ стоит применять с осторожностью, так как кодировка CESU-8 по-иному обрабатывает некоторые специфические символы (суррогатные пары), выходящие за пределы базовой многоязычной плоскости Юникода. Если в ваших данных только стандартная кириллица и латиница, это сработает отлично.

Итоги

Мы проанализировали ситуацию, когда казалось бы корректный код в 1С вызывает ошибки на принимающей стороне. Запомните главное правило: при работе с REST API и отправке JSON форматов из 1С, всегда явно контролируйте отсутствие Byte Order Mark (BOM). Использование конструкции ИспользованиеByteOrderMark.НеИспользовать избавит вас от долгих часов отладки "невидимых" символов и поиска проблем в сетевом оборудовании.

← На главную