Интеграции в 1С

Непредвиденный символ при чтении JSON в 1С: диагностика ошибки ПрочитатьJSON

Коротко

«Непредвиденный символ при чтении JSON» — это ошибка парсера ПрочитатьJSON, которую 1С 8.3 бросает, когда встречает байт вне грамматики JSON. Проверьте по порядку: BOM в начале строки/файла (символ с кодом 65279, байты EF BB BF), кодировку ответа (UTF-8, а не windows-1251) и что сервер действительно вернул JSON, а не HTML-страницу ошибки или XML.

Позицию символа удобно смотреть через свойства ТекущаяСтрока и ТекущаяПозиция объекта ЧтениеJSON в блоке Попытка…Исключение. Если строка приходит от внешнего HTTP-сервиса — сначала сохраните её в файл и прогоните через онлайн-валидатор (jsonlint), это в разы ускоряет диагностику.

Причина №1: BOM в начале файла или строки

Самая частая причина ошибки «непредвиденный символ при чтении json 1с» — метка порядка байтов (Byte Order Mark, BOM). Это три байта EF BB BF в начале UTF-8 файла, невидимые в текстовом редакторе, но JSON-грамматика их не допускает: JSON должен начинаться с {, [, ", цифры, true, false или null. Парсер ПрочитатьJSON видит невидимый символ и падает на позиции 1.

Если данные пришли строкой, уберите BOM через СтрЗаменить с символом 65279:

Функция УдалитьBOM(Строка)
    Возврат СтрЗаменить(Строка, Символ(65279), "");
КонецФункции

// Использование:
Ответ = HTTPОтвет.ПолучитьТелоКакСтроку("UTF-8");
    Ответ = УдалитьBOM(Ответ);

ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Ответ);
Данные = ПрочитатьJSON(ЧтениеJSON, Истина);
ЧтениеJSON.Закрыть();

Второй сценарий — читаем файл с диска, в котором «зашит» BOM. Здесь помогает промежуточное чтение через ЧтениеТекста с явной кодировкой: 1С сама пропускает BOM для UTF-8, если кодировку указать корректно.

Чтение = Новый ЧтениеТекста;
Чтение.Открыть("C:\Exchange\data.json", "UTF-8");
СтрокаJSON = Чтение.Прочитать();
Чтение.Закрыть();

ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрЗаменить(СтрокаJSON, Символ(65279), ""));
Данные = ПрочитатьJSON(ЧтениеJSON, Истина);
ЧтениеТекста.Открыть
ИмяФайлапуть к файлу с JSON
Кодировка"UTF-8", "windows-1251" и т. п.
РазделительСтрокпо умолчанию — системный
КонвертируемыйРазделительСтроквнутренний CRLF
МонопольныйРежимэксклюзивный доступ к файлу
→ ничего не возвращает

При формировании JSON на стороне 1С (например, тело HTTP-ответа) укажите ИспользованиеByteOrderMark.НеИспользовать при получении строки — это стандартная рекомендация 1С для JSON, чтобы принимающая сторона не столкнулась с той же проблемой.

Как это в Консоли кода

В Консоли кода AI-агент видит и код чтения JSON, и живой ответ внешнего сервиса: он сам находит BOM, «умные» кавычки и подсказывает, нужно ли читать в Соответствие или Структуру — без ручной отладки в конфигураторе.

Попросите агента: «Мой ПрочитатьJSON падает на первом символе — покажи, есть ли BOM в ответе HTTP-сервиса, и как его убрать перед разбором».

Причина №2: неверная кодировка (cp1251 вместо UTF-8)

Вторая по частоте причина ошибки «1с прочитатьjson» — кодировка. JSON по стандарту RFC 8259 всегда в Unicode (по умолчанию UTF-8). Если внешний сервис отдаёт cp1251, а вы читаете тело как UTF-8, кириллические байты превращаются в мусор и парсер падает на первом «сломанном» символе внутри строки.

Как проверить и починить:

// Смотрим заголовок Content-Type
Заголовок = HTTPОтвет.Заголовки["Content-Type"]; // "application/json; charset=windows-1251"

// Если сервер честно указал charset — берём именно его
   Ответ = HTTPОтвет.ПолучитьТелоКакСтроку("windows-1251");

// Если Content-Type не указан, но данные явно битые — попробуйте обе кодировки
Попытка
    Ответ = HTTPОтвет.ПолучитьТелоКакСтроку("UTF-8");
    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(Ответ);
    Данные = ПрочитатьJSON(ЧтениеJSON, Истина);
Исключение
    Ответ = HTTPОтвет.ПолучитьТелоКакСтроку("windows-1251");
    ЧтениеJSON = Новый ЧтениеJSON;
       ЧтениеJSON.УстановитьСтроку(Ответ);
    Данные = ПрочитатьJSON(ЧтениеJSON, Истина);
КонецПопытки;

Если работаете с файлом — вместо ЧтениеJSON.ОткрытьФайл() без параметров используйте вариант с явной кодировкой:

ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.ОткрытьФайл("C:\Exchange\data.json", "UTF-8");
   Данные = ПрочитатьJSON(ЧтениеJSON, Истина);
ЧтениеJSON.Закрыть();
ЧтениеJSON.ОткрытьФайл
ИмяФайлаполный путь к JSON-файлу
Кодировкапо умолчанию "UTF-8", можно "windows-1251"
→ ничего не возвращает

Причина №3: сервер вернул не JSON, а HTML или XML

Классический кейс с форумов mista и infostart: HTTP-запрос возвращает КодСостояния = 200, но в теле — HTML-страница с ошибкой авторизации, капча, редирект или XML. ЧтениеJSON видит < первым символом и сообщает «непредвиденный символ при чтении json 1с ошибка» на позиции 1.

Всегда логируйте первые 200 символов ответа перед разбором:

Ответ = HTTPОтвет.ПолучитьТелоКакСтроку("UTF-8");

   // Диагностическая проверка — что реально пришло
Если СтрНачинаетсяС(СокрЛП(Ответ), "<") Тогда
    ВызватьИсключение "Сервер вернул не JSON: " + Лев(Ответ, 200);
КонецЕсли;

ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Ответ);
Данные = ПрочитатьJSON(ЧтениеJSON, Истина);

Если у API есть параметр формата (format=json vs format=xml) — убедитесь, что запрашиваете именно JSON. Проверяйте и заголовок Accept: application/json — некоторые сервисы по умолчанию отдают XML.

Причина №4: одинарные кавычки и ключи без кавычек

JSON-грамматика допускает только двойные кавычки (") вокруг ключей и строк. Но многие API и особенно «браузерные» источники возвращают JavaScript-объектный литерал: ключи без кавычек либо в одинарных кавычках, «умные» кавычки из Word («, »). Такой контент 1С не прожуёт.

Минимальная нормализация перед разбором (не серебряная пуля, но снимает 80% случаев):

// Меняем «умные» кавычки (U+00AB «, U+00BB », U+201C “, U+201D ”) на обычные
Ответ = СтрЗаменить(Ответ, Символ(171), """"); // «
Ответ = СтрЗаменить(Ответ, Символ(187), """"); // »
Ответ = СтрЗаменить(Ответ, Символ(8220), """"); // “
Ответ = СтрЗаменить(Ответ, Символ(8221), """"); // ”

// Если абсолютно уверены, что в значениях нет одинарных кавычек:
Ответ = СтрЗаменить(Ответ, "'", """");

ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Ответ);
Данные = ПрочитатьJSON(ЧтениеJSON, Истина);

Если контент нестандартный систематически — заведите свой парсер на регулярках или попросите поставщика API вернуть корректный JSON. Массовый СтрЗаменить ломает данные, где одинарная кавычка — часть значения (апострофы, тексты).

Причина №5: числовые ключи и дефисы в именах — читайте в Соответствие

Отдельный подкласс ошибки, который на форумах часто путают с «непредвиденным символом»: парсер отработал, но упал на этапе преобразования в структуру с текстом Недопустимое имя свойства. Причина — второй параметр ПрочитатьJSON(ЧтениеJSON, ПрочитатьВСоответствие). Если оставить его Ложь (по умолчанию), 1С пытается положить ключи в структуру, а имя поля структуры не может начинаться с цифры или содержать дефис ("0", "tem-53", "@id").

// Правильно: читаем в Соответствие, а не в Структуру
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Ответ);
Данные = ПрочитатьJSON(ЧтениеJSON, Истина); // ← ключевой параметр
   
// Обращение — как к Соответствию
Заказ = Данные["response"]["orders"]["tem-53"];
Сумма = Заказ["amount"];
ПрочитатьJSON (глобальный)
ЧтениеJSONинициализированный объект-читатель
ПрочитатьВСоответствиеИстина — если ключи не годятся в имена свойств
ИменаСвойствСоЗначениямиДатамассив ключей с датами
ОжидаемыйФорматДатыФорматДатыJSON.ISO / Microsoft
МаксимальнаяВложенностьзащита от чрезмерно вложенных структур
Произвольный (Структура/Соответствие/Массив/примитив)

Причина №6: вложенный JSON-строкой без экранирования

Реальный кейс с infostart: сервис отдаёт поле additional_data, куда «зашит» ещё один JSON, но кавычки внутри не экранированы. Итоговая строка невалидна:

{
    "order_number": "tem-53",
    "additional_data": "{"email":"user@mipt.ru","fullName":"ФИО"}"
}

ЧтениеJSON увидит закрывающую " после { и решит, что значение закончилось, а дальше пойдёт «непредвиденный символ». Правильно было бы экранировать: "additional_data": "{\"email\":\"user@mipt.ru\"}".

Если API чинить нельзя — вытащите проблемное значение регуляркой до ПрочитатьJSON и разберите его отдельно:

// Грубая изоляция вложенного объекта по маркеру
ПозицияДопДанных = СтрНайти(Ответ, """additional_data"":");
// … дальше выделяем подстроку от первой { до парной } и парсим её отдельным ЧтениеJSON.

// Более чистый путь — предварительно экранировать кавычки внутри значения:
Ответ = СтрЗаменить(Ответ, ": ""{", ": ""{"); // маркер начала
// … нормализация зависит от конкретного формата API.

Причина №7: управляющие и невидимые символы внутри значений

JSON запрещает «сырые» управляющие символы (табы, переносы строк, возврат каретки) внутри строковых значений — они должны быть экранированы как \t, \n, \r. Если сервер вернул многострочный комментарий «как есть», парсер сообщит «непредвиденный символ» и укажет позицию невидимого байта.

Плюс встречаются «мусорные» коды: Символ(0) (нулевой байт), NBSP (Символ(160)), zero-width space (Символ(8203)). Их удобно вычистить одной функцией перед УстановитьСтроку:

Функция ОчиститьСлужебные(Строка)
    Результат = Строка;
    Для Каждого КодСимвола Из Новый Массив(0, 8203, 65279) Цикл
        Результат = СтрЗаменить(Результат, Символ(КодСимвола), "");
    КонецЦикла;
    Возврат Результат;
КонецФункции

Как найти точную позицию «плохого» символа

Когда причина не очевидна, найдите позицию, на которой падает ПрочитатьJSON — так быстрее любых догадок. У объекта ЧтениеJSON есть свойства ТекущаяПозиция и ТекущаяСтрока, которые доступны и в исключении:

ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Ответ);

Попытка
    Данные = ПрочитатьJSON(ЧтениеJSON, Истина);
   Исключение
    Позиция  = ЧтениеJSON.ТекущаяПозиция;
    НомерСтр = ЧтениеJSON.ТекущаяСтрока;
    Окно     = Сред(Ответ, Макс(Позиция - 30, 1), 60);
    ЗаписьЖурналаРегистрации(
        "JSON.parse",
        УровеньЖурналаРегистрации.Ошибка,
        ,,
        "Строка " + НомерСтр + ", позиция " + Позиция + ", контекст: [" + Окно + "]"
    );
       ВызватьИсключение;
КонецПопытки;

Дополнительный приём для «трудных» ответов — сохранить сырое тело в файл и открыть его в редакторе с показом невидимых символов (Notepad++, VS Code с плагином Gremlins), либо прогнать через jsonlint.com — валидатор укажет строку и колонку ошибки в человеческом виде.

Как это в Консоли кода

Прямо из чата AI-агент дёрнет ПрочитатьJSON на живой строке, поймает исключение, покажет ТекущаяПозиция, окно вокруг ошибки и подскажет, что нормализовать: BOM, кавычки, кодировку или структуру.

Попросите агента: «Прогони мой ответ HTTP через ПрочитатьJSON, найди позицию непредвиденного символа и подскажи, чем это чинить».

Частые ошибки при чтении JSON в 1С 8.3

  • Забыли закрыть ЧтениеJSON.Закрыть(). Не приводит к «непредвиденному символу», но течёт файловый дескриптор при чтении файлов.
  • Игнорируют второй параметр ПрочитатьJSON. Оставляют Ложь, получают «недопустимое имя свойства» на числовых ключах вроде "0" и "200". Ставьте Истина, если ключи приходят «как есть» из внешнего API.
  • Читают ответ как ПолучитьТелоКакСтроку() без кодировки. 1С использует системную кодировку сервера — на linux это UTF-8, на Windows-сервере часто cp1251. Всегда указывайте кодировку явно.
  • Не отделяют HTTP-ошибки от бизнес-ошибок. Сначала проверяйте КодСостояния, потом Content-Type, и только потом парсите JSON — иначе получите непредвиденный символ на HTML-странице ошибки.
  • Используют JSONP-обёртку callback({...}) как JSON. Обрежьте префикс и последнюю ) до УстановитьСтроку.
  • Trailing comma в объекте/массиве. {"a":1,} — невалидный JSON, хотя JavaScript такое принимает. Либо чините источник, либо подчищайте регуляркой перед разбором.

Чек-лист диагностики: 5 шагов от ошибки к рабочему разбору

  • 1. Залогируйте первые 200 символов сырого ответа и сравните с ожидаемым JSON.
  • 2. Проверьте КодСостояния и Content-Type HTTP-ответа.
  • 3. Явно укажите кодировку в ПолучитьТелоКакСтроку("UTF-8").
  • 4. Уберите BOM: СтрЗаменить(Ответ, Символ(65279), "").
  • 5. В ПрочитатьJSON вторым параметром поставьте Истина — читайте в Соответствие.

Этих пяти шагов достаточно, чтобы закрыть подавляющую часть жалоб на «прочитатьjson 1с 8.3 непредвиденный символ». Если после этого падение остаётся — смотрите позицию через ТекущаяПозиция и работайте с конкретным байтом.

Частые вопросы про «Непредвиденный символ при чтении JSON» в 1С

Как в 1С убрать BOM перед ПрочитатьJSON?

Если данные уже в строке — вызовите СтрЗаменить(Строка, Символ(65279), "") до УстановитьСтроку. Если читаете файл — используйте ЧтениеТекста с явной кодировкой "UTF-8" или ЧтениеJSON.ОткрытьФайл(Путь, "UTF-8"): платформа сама пропустит BOM.

Почему ПрочитатьJSON падает, хотя строка валидна на jsonlint?

Скорее всего вы читаете тело HTTP-ответа в неверной кодировке (например, UTF-8, когда сервер отдал cp1251). Проверьте заголовок Content-Type и передайте нужную кодировку в ПолучитьТелоКакСтроку — символы кириллицы перестанут превращаться в мусор.

Как найти позицию непредвиденного символа при чтении JSON?

Оберните ПрочитатьJSON в Попытка…Исключение и в блоке исключения прочитайте ЧтениеJSON.ТекущаяПозиция и ЧтениеJSON.ТекущаяСтрока. Дальше вырежьте окно Сред(Ответ, Позиция - 30, 60) — этого хватает, чтобы увидеть проблемный байт в контексте.