Как правильно перекодировать текст из HTTP-ответа в 1С 8.3 на Linux

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

При интеграции 1С с внешними API (например, сервисами ФНС egrul.nalog.ru или dadata.ru) разработчики часто сталкиваются с проблемой некорректного отображения кириллицы. Вместо привычного текста приходят «кракозябры» вида Реобходимо. Традиционные способы решения через COM-объект ADODB.Stream или MSScriptControl отлично работают на Windows, но абсолютно бесполезны на серверах под управлением Linux. Разберем, как элегантно решить задачу перекодировки средствами платформы 8.3.11 и выше.

Выясним причину появления «кракозябр»

Ситуация, которую мы видим (символы Ð и аналогичные), называется Double UTF-8 или ошибочная интерпретация UTF-8 как ISO-8859-1. Это происходит, когда сервер присылает данные в UTF-8, но 1С (или промежуточный узел) считывает их байт за байтом, полагая, что это однобайтовая кодировка. В результате каждый байт кириллического символа превращается в отдельный символ латиницы с расширенным кодом. Для исправления ситуации нам нужно заставить 1С правильно интерпретировать массив байтов (двоичные данные).

Способ 1: Использование временного файла (универсальный метод)

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


// Выполняем запрос к сервису
Соединение = Новый HTTPСоединение("egrul.nalog.ru",,,,, 30, Новый ЗащищенноеСоединениеOpenSSL());
Запрос = Новый HTTPЗапрос("/путь_к_api");
Ответ = Соединение.Получить(Запрос);

Если Ответ.КодСостояния = 200 Тогда
    // Получаем тело ответа как двоичные данные, чтобы избежать автоматической перекодировки
    ДанныеТела = Ответ.ПолучитьТелоКакДвоичныеДанные();
    
    // Генерируем путь к временному файлу
    ИмяФайла = ПолучитьИмяВременногоФайла("txt");
    ДанныеТела.Записать(ИмяФайла);
    
    // Читаем файл, явно указав кодировку UTF-8
    ТекстДокумента = Новый ЧтениеТекста;
    ТекстДокумента.Открыть(ИмяФайла, КодировкаТекста.UTF8);
    РезультатСтрокой = ТекстДокумента.Прочитать();
    ТекстДокумента.Закрыть();
    
    // Удаляем временный файл
    УдалитьФайлы(ИмяФайла);
    
    // Теперь РезультатСтрокой содержит нормальный русский текст
КонецЕсли;

Почему это работает: При записи ДвоичныеДанные в файл платформа не пытается анализировать их содержимое. При последующем вызове ЧтениеТекста.Открыть() с параметром КодировкаТекста.UTF8 1С корректно собирает многобайтовые символы кириллицы. Использование временного файла на Linux-серверах эффективно, так как современные файловые системы (например, ext4) отлично кэшируют операции с мелкими временными файлами.

Способ 2: Прямая конвертация в памяти (для платформы 8.3.10 и выше)

Рассмотрим более современный и производительный метод, который не требует обращения к дисковой подсистеме. Начиная с версии 8.3.10, в 1С появились функции для прямой работы с кодировками в оперативной памяти. Проанализируем пример кода:


Ответ = Соединение.Получить(Запрос);
Если Ответ.КодСостояния = 200 Тогда
    ДвоичныеДанные = Ответ.ПолучитьТелоКакДвоичныеДанные();
    
    // Используем метод платформы для перекодировки без файлов
    СтрокаJSON = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанные, КодировкаТекста.UTF8);
    
    // Теперь можно сразу передавать строку в парсер JSON
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(СтрокаJSON);
    Данные = ПрочитатьJSON(Чтение);
    Чтение.Закрыть();
КонецЕсли;

Метод ПолучитьСтрокуИзДвоичныхДанных является идеальной заменой ADODB.Stream. Он работает внутри процесса 1С, не зависит от операционной системы и корректно обрабатывает BOM (Byte Order Mark).

Способ 3: Обработка JSON напрямую из потока

Если ваша цель — десериализация JSON, полученного от сервиса, то лучше всего использовать связку Поток и ЧтениеJSON. Это самый быстрый способ, так как данные обрабатываются конвейерно. Посмотрим на реализацию:


Ответ = Соединение.Получить(Запрос);
Если Ответ.КодСостояния = 200 Тогда
    // Получаем поток чтения напрямую из тела ответа
    Поток = Ответ.ПолучитьТелоКакПоток();
    
    Чтение = Новый ЧтениеJSON;
    // Указываем кодировку UTF-8 прямо при открытии потока
    Чтение.ОткрытьПоток(Поток, КодировкаТекста.UTF8);
    
    ДанныеJSON = ПрочитатьJSON(Чтение);
    Чтение.Закрыть();
    Поток.Закрыть();
КонецЕсли;

Использование объекта Поток позволяет избежать создания огромных строк в памяти, что критично при получении больших объемов данных от API. Платформа самостоятельно позаботится о преобразовании байтов в символы в процессе чтения структуры JSON.

Как бороться с нестандартными кодировками вручную

В редких случаях, когда API присылает данные в экзотических кодировках (например, старые государственные реестры), и встроенные методы не справляются, программисты прибегают к ручному пересчету кодов символов. Посмотрим на алгоритм, предложенный в сообществе для коррекции кодов кириллицы:


Функция ИсправитьКириллицу(БитаяСтрока)
    Рез = "";
    Для ии = 1 По СтрДлина(БитаяСтрока) Цикл
        КодСимв = КодСимвола(Сред(БитаяСтрока, ии, 1));
        // Смещение для символов кириллицы в некоторых кодировках
        Если КодСимв >= 192 И КодСимв <= 255 Тогда
            Рез = Рез + Символ(КодСимв + 848);
        Иначе
            Рез = Рез + Символ(КодСимв);
        КонецЕсли;
    КонецЦикла;
    Возврат Рез;
КонецФункции

Важное замечание: Этот метод является "костылем" и должен использоваться только в крайнем случае, когда стандартные ПолучитьСтрокуИзДвоичныхДанных или ЧтениеТекста не дают результата. Он предполагает, что вы точно знаете величину смещения в таблице кодировок.

Рекомендации по настройке HTTP-запроса

Чтобы минимизировать проблемы с кодировкой на стороне сервера, всегда явно указывайте в заголовках запроса, в каком формате вы ожидаете получить ответ. Для этого используйте объект HTTPЗапрос:

  1. Установите заголовок Accept-Charset: Запрос.Заголовки.Вставить("Accept-Charset", "utf-8");
  2. Установите заголовок Accept: Запрос.Заголовки.Вставить("Accept", "application/json; charset=utf-8");
  3. Если сервер требует авторизации или передачи данных, убедитесь, что Content-Type также содержит указание кодировки.

Разберем, почему это важно. Если сервер видит, что клиент поддерживает только utf-8, он с меньшей вероятностью применит автоматическую перекодировку в ISO-8859-1 при передаче через прокси-серверы, что часто и является причиной "сломанного" текста в Linux-системах.

Резюме: Для современных конфигураций на платформе 8.3.11 и выше самым правильным решением будет использование ПолучитьСтрокуИзДвоичныхДанных(Тело, КодировкаТекста.UTF8). Это избавляет от необходимости использовать внешние компоненты, зависимости от ОС и временные файлы, обеспечивая максимальную скорость работы кода.

← На главную