При работе с внешними API через встроенный язык 1С:Предприятие программисты часто сталкиваются с ситуацией, когда при выполнении HTTPЗапрос метод ПолучитьТелоКакСтроку() возвращает нечитаемый набор байтов, хотя в сторонних инструментах, таких как Postman, тот же самый запрос возвращает корректный текст или JSON. Рассмотрим, почему это происходит, и разберем по шагам способы решения этой проблемы.
Проанализируем ситуацию: если ответ сервера выглядит как хаотичный набор символов (например, X[oH +_Ds), это чаще всего означает, что данные передаются в сжатом виде. За это отвечает механизм HTTP Compression.
Когда мы отправляем запрос, мы можем указать заголовок Accept-Encoding. Этот заголовок сообщает серверу, какие алгоритмы сжатия понимает наш клиент (1С). Если в коде указано:
Заголовки.Вставить("Accept-Encoding", "gzip");
Сервер, видя этот заголовок, сжимает JSON-ответ с помощью алгоритма GZip для экономии трафика. Проблема заключается в том, что платформа 1С не всегда автоматически распаковывает полученные двоичные данные перед тем, как превратить их в строку. В результате метод ПолучитьТелоКакСтроку() пытается интерпретировать сжатый архив как обычный текст в кодировке UTF-8, что и приводит к появлению нечитаемых символов.
Самый простой способ исправить ситуацию — это попросить сервер присылать данные в обычном, несжатом виде. Для этого достаточно изменить или удалить заголовок Accept-Encoding.
Рассмотрим пример кода, который часто «взлетает» у разработчиков:
// Вместо gzip указываем некорректное значение или вовсе удаляем заголовок
Заголовки.Вставить("Accept-Encoding", "identity");
// Или можно просто не добавлять этот заголовок в соответствие
Важное замечание: некоторые сервера при получении в Accept-Encoding значения application/json (как в примере из обсуждения на форуме) просто игнорируют его, так как это не алгоритм сжатия, а MIME-тип. В этом случае сервер понимает, что клиент «не умеет» в сжатие, и отправляет данные в открытом виде (identity). Однако правильнее будет использовать заголовок Accept для указания типа контента и Accept-Encoding: identity для управления сжатием.
Если вы работаете с большими объемами данных (например, загружаете детальную статистику), сжатие gzip крайне желательно для стабильности соединения и скорости работы. В этом случае мы не будем отключать сжатие на сервере, а научим 1С правильно обрабатывать результат.
Разберем процесс по шагам:
ЧтениеGZip для распаковки файла.Посмотрим на пример реализации такого подхода:
Запрос = Новый HTTPЗапрос(СтрокаЗапроса, Заголовки);
Ответ = Соединение.Получить(Запрос);
Если Ответ.КодСостояния = 200 Тогда
// Получаем сжатые данные
СжатыеДанные = Ответ.ПолучитьТелоКакДвоичныеДанные();
// Путь для временных файлов
ИмяФайлаСжатый = ПолучитьИмяВременногоФайла("gz");
ИмяФайлаРаспакованный = ПолучитьИмяВременногоФайла("json");
СжатыеДанные.Записать(ИмяФайлаСжатый);
// Распаковка
ПотокЧтения = Новый ЧтениеGZip(ИмяФайлаСжатый);
ПотокЗаписи = Новый ЗаписьДанных(ИмяФайлаРаспакованный);
// Перекачиваем данные из сжатого потока в обычный файл
ПотокЗаписи.Записать(ПотокЧтения.Прочитать());
ПотокЗаписи.Закрыть();
ПотокЧтения.Закрыть();
// Теперь читаем результат как строку
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.Прочитать(ИмяФайлаРаспакованный, КодировкаТекста.UTF8);
РезультатТекст = ТекстовыйДокумент.ПолучитьТекст();
// Удаляем временные файлы
УдалитьФайлы(ИмяФайлаСжатый);
УдалитьФайлы(ИмяФайлаРаспакованный);
КонецЕсли;
Чтобы окончательно убедиться, что проблема именно в сжатии, проанализируем заголовки, которые приходят от сервера. Мы можем сделать это прямо в отладчике 1С, изучив свойство Ответ.Заголовки.
Если в заголовках ответа вы видите Content-Encoding: gzip, это стопроцентное подтверждение того, что тело ответа нужно предварительно распаковывать. Если же Content-Encoding отсутствует или равен identity, значит проблема в кодировке текста (UTF-8, Windows-1251 и т.д.).
Стоит отметить, что в последних релизах платформы 1С 8.3 реализована попытка автоматической обработки Content-Encoding. Однако она работает не во всех случаях (зависит от версии платформы, режима совместимости и конкретной реализации веб-сервера). Если вы используете метод Ответ.ПолучитьТелоКакСтроку(), платформа пытается угадать формат данных.
Безопаснее всего при работе с внешними интеграциями использовать получение данных во временный файл через метод HTTPСоединение.Получить(Запрос, ИмяВыходногоФайла). Это позволяет:
1F 8B — перед вами архив GZip.ЧтениеТекста или ТекстовыйДокумент.Проанализировав ситуацию, мы можем выделить три правила успешной работы с HTTP-запросами в 1С:
Accept-Encoding: gzip, deflate, br может запутать 1С, так как поддержка алгоритма br (Brotli) появилась далеко не сразу.Content-Type: Если вы ожидаете JSON, убедитесь, что сервер прислал именно его.1cv8.exe и увидеть «сырой» ответ сервера без искажений со стороны платформы.Следуя этим правилам, вы сможете легко диагностировать любые проблемы с кодировками и форматами данных при интеграции с внешними системами.