Почему в 1С при чтении JSON буква «о» заменяется на «п» и как это исправить?

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

При интеграции 1С с внешними веб-сервисами через HTTP-запросы программисты иногда сталкиваются с крайне странным поведением системы: данные приходят, но некоторые буквы в словах оказываются заменены на другие. Самый яркий пример — замена строчной «о» на «п». В результате вместо слова «хром» мы получаем «хрпм», а вместо корректного артикула — искаженную строку. На первый взгляд это кажется багом платформы или проблемой кодировки самого JSON-файла, однако причина кроется гораздо глубже — в правилах формирования URL-адреса и обработке спецсимволов.

В данной статье мы подробно разберем, почему возникает такая «битовая ошибка», проанализируем механизм искажения данных и рассмотрим правильный способ формирования HTTP-запросов в 1С, который исключит подобные проблемы в будущем.

Выясняем причину: почему «о» превращается в «п»?

Для начала проанализируем техническую сторону вопроса. Если мы обратимся к таблице кодировки Unicode (UTF-8), которую использует 1С и большинство веб-серверов для передачи JSON, мы увидим следующее:

  1. Буква «о» имеет код U+043E.
  2. Буква «п» имеет код U+043F.

Разница между этими символами составляет ровно 1 бит в младшем разряде. Такое «смещение» на единицу практически никогда не бывает случайным. Оно возникает, когда поток байтов интерпретируется некорректно из-за сдвига указателя чтения или неверной обработки управляющих последовательностей. В рассматриваемом случае в параметре запроса присутствовал символ обратного слэша \.

Когда вы отправляете строку вида sku=14980-0YXRgNC\0Lw= без предварительной обработки, веб-сервер (например, Nginx или Apache) может воспринять комбинацию \0 как управляющий символ null-terminator (признак конца строки в языке C). Это ломает логику парсинга строки на стороне сервера или промежуточного шлюза, что приводит к искажению последующих байтов при чтении данных из базы или кэша. В результате один бит «теряется» или «прилипает», и ваша «о» превращается в «п».

Разбор типичной ошибки в коде

Рассмотрим фрагмент кода, который чаще всего приводит к подобным проблемам. Проблема здесь заключается в «склеивании» строки запроса напрямую с параметрами:


// ОПАСНЫЙ КОД
ИДМаркета = "14980-0YXRgNC\0Lw="; // Содержит опасный символ \
СтрокаПараметраПолучения = "/api-1c/market-sku-info?sku=" + ИДМаркета; 
СерверИсточник = "ultrasport.ru";

HTTP = Новый HTTPСоединение(СерверИсточник, , , , , , Новый ЗащищенноеСоединениеOpenSSL());
Результат = HTTP.Получить(Новый HTTPЗапрос(СтрокаПараметраПолучения));

// Здесь в ответе мы можем получить "хрпм" вместо "хром"
Ответ = Результат.ПолучитьТелоКакСтроку();

Почему в браузере этот же запрос работает корректно? Современные браузеры (Chrome, Firefox, Safari) при вводе адреса автоматически выполняют URL-encoding. Они «под капотом» заменяют символ \ на его безопасный эквивалент %5C. 1С в объекте HTTPСоединение этого автоматически не делает — она отправляет строку ровно в том виде, в котором вы её сформировали. Если в строке есть пробелы, кириллица или спецсимволы (\, &, #), сервер может интерпретировать запрос непредсказуемо.

Решение №1: Обязательное кодирование параметров URL

Правильный способ решения задачи — использование функции КодироватьСтроку с параметром СпособКодированияСтроки.КодировкаURL. Это гарантирует, что все небезопасные символы будут заменены на их шестнадцатеричные коды, понятные любому веб-серверу.

Разберем исправленный код по шагам:


// 1. Исходные данные
ИДМаркета = "14980-0YXRgNC\0Lw="; 

// 2. Кодируем только ПАРАМЕТР, а не весь URL целиком
// Это превратит "\" в "%5C", а "=" в "%3D"
ЗакодированныйИД = КодироватьСтроку(ИДМаркета, СпособКодированияСтроки.КодировкаURL);

// 3. Формируем строку запроса
ПутьКРесурсу = "/api-1c/market-sku-info?sku=" + ЗакодированныйИД;

// 4. Выполняем запрос
СерверИсточник = "ultrasport.ru";
Попытка
    HTTP = Новый HTTPСоединение(СерверИсточник, , , , , , Новый ЗащищенноеСоединениеOpenSSL());
    Запрос = Новый HTTPЗапрос(ПутьКРесурсу);
    Результат = HTTP.Получить(Запрос);
    
    Если Результат.КодСостояния = 200 Тогда
        // Явно указываем кодировку UTF-8 для исключения проблем на разных ОС
        Ответ = Результат.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
        
        // Читаем JSON
        ЧтениеJSON = Новый ЧтениеJSON;
        ЧтениеJSON.УстановитьСтроку(Ответ);
        Данные = ПрочитатьJSON(ЧтениеJSON);
        ЧтениеJSON.Закрыть();
        
        Артикул = Данные.artikul; // Теперь вернет "хром"
        Модель = Данные.model;
    КонецЕсли;
Исключение
    Сообщить("Ошибка связи: " + ОписаниеОшибки());
КонецПопытки;

Решение №2: Правильная работа с телом ответа

Иногда искажение символов может происходить не на этапе отправки запроса, а на этапе интерпретации ответа. Метод ПолучитьТелоКакСтроку() без параметров пытается определить кодировку автоматически. Он ориентируется на заголовок Content-Type от сервера или на наличие метки BOM.

Если сервер настроен некорректно и не присылает charset=utf-8 в заголовках, 1С может использовать региональную кодировку системы (например, Windows-1251 для русской Windows), что также приведет к «каше» из символов. Поэтому всегда указывайте кодировку явно, если вы точно знаете, что сервер возвращает данные в UTF-8:

Ответ = Результат.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);

Рекомендации по безопасности и стабильности интеграций

Проанализировав данную проблему, мы можем сформулировать несколько «золотых правил» для работы с HTTP в 1С:

  1. Никогда не доверяйте входящим данным. Если значение параметра (артикул, ID, поисковый запрос) приходит из базы данных или от пользователя, оно обязано пройти через КодироватьСтроку перед попаданием в URL.
  2. Разделяйте базовый адрес и параметры. Старайтесь не формировать длинные строки запроса «вручную». Если параметров много, удобно использовать соответствие или структуру, обходя её в цикле и собирая строку с кодированием каждого значения.
  3. Проверяйте заголовки сервера. Используйте отладчик, чтобы посмотреть Результат.Заголовки. Если сервер присылает данные в одной кодировке, а вы читаете в другой — ошибки неизбежны.
  4. Используйте современные инструменты. Если в вашей конфигурации есть библиотека стандартных подсистем (БСП), обратите внимание на модуль ОбщегоНазначения или специализированные библиотеки-коннекторы, которые берут на себя рутину по экранированию спецсимволов.

Использование метода КодироватьСтроку(..., СпособКодированияСтроки.КодировкаURL) — это не просто способ исправить замену «о» на «п», это стандарт индустрии, который защищает ваш код от поломок при наличии в данных таких символов, как & (который разделил бы ваш артикул на два разных параметра) или # (который обрезал бы весь хвост запроса на стороне сервера).

← На главную