При интеграции 1С с внешними веб-сервисами через HTTP-запросы программисты иногда сталкиваются с крайне странным поведением системы: данные приходят, но некоторые буквы в словах оказываются заменены на другие. Самый яркий пример — замена строчной «о» на «п». В результате вместо слова «хром» мы получаем «хрпм», а вместо корректного артикула — искаженную строку. На первый взгляд это кажется багом платформы или проблемой кодировки самого JSON-файла, однако причина кроется гораздо глубже — в правилах формирования URL-адреса и обработке спецсимволов.
В данной статье мы подробно разберем, почему возникает такая «битовая ошибка», проанализируем механизм искажения данных и рассмотрим правильный способ формирования HTTP-запросов в 1С, который исключит подобные проблемы в будущем.
Для начала проанализируем техническую сторону вопроса. Если мы обратимся к таблице кодировки Unicode (UTF-8), которую использует 1С и большинство веб-серверов для передачи JSON, мы увидим следующее:
U+043E.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Соединение этого автоматически не делает — она отправляет строку ровно в том виде, в котором вы её сформировали. Если в строке есть пробелы, кириллица или спецсимволы (\, &, #), сервер может интерпретировать запрос непредсказуемо.
Правильный способ решения задачи — использование функции КодироватьСтроку с параметром СпособКодированияСтроки.Кодировка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;
КонецЕсли;
Исключение
Сообщить("Ошибка связи: " + ОписаниеОшибки());
КонецПопытки;
Иногда искажение символов может происходить не на этапе отправки запроса, а на этапе интерпретации ответа. Метод ПолучитьТелоКакСтроку() без параметров пытается определить кодировку автоматически. Он ориентируется на заголовок Content-Type от сервера или на наличие метки BOM.
Если сервер настроен некорректно и не присылает charset=utf-8 в заголовках, 1С может использовать региональную кодировку системы (например, Windows-1251 для русской Windows), что также приведет к «каше» из символов. Поэтому всегда указывайте кодировку явно, если вы точно знаете, что сервер возвращает данные в UTF-8:
Ответ = Результат.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
Проанализировав данную проблему, мы можем сформулировать несколько «золотых правил» для работы с HTTP в 1С:
КодироватьСтроку перед попаданием в URL.Результат.Заголовки. Если сервер присылает данные в одной кодировке, а вы читаете в другой — ошибки неизбежны.ОбщегоНазначения или специализированные библиотеки-коннекторы, которые берут на себя рутину по экранированию спецсимволов.Использование метода КодироватьСтроку(..., СпособКодированияСтроки.КодировкаURL) — это не просто способ исправить замену «о» на «п», это стандарт индустрии, который защищает ваш код от поломок при наличии в данных таких символов, как & (который разделил бы ваш артикул на два разных параметра) или # (который обрезал бы весь хвост запроса на стороне сервера).