Как распаковать данные в формате GZIP при получении с сервера в 1С

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

При активном обмене данными с веб-сервисами разработчики часто сталкиваются с ситуацией, когда сервер в целях экономии трафика возвращает ответ, сжатый алгоритмом GZIP. Если попытаться прочитать такой ответ стандартным методом responseText, мы получим нечитаемый набор символов ("кракозябры"). Это происходит потому, что сжатые данные являются бинарными, а попытка интерпретировать их как текст приводит к искажению структуры файла.

В этой статье мы подробно разберем, как корректно получить сжатые данные, сохранить их на диск и распаковать, используя возможности платформы 1С и системные компоненты Windows. Мы проанализируем несколько подходов: от управления заголовками запроса до использования внешних архиваторов.

Причина проблемы: ResponseText против ResponseBody

Прежде всего, выясним причину, по которой обычный метод чтения текста не работает. Когда мы используем объект WinHttp.WinHttpRequest.5.1, у нас есть два способа получить тело ответа:

  1. responseText — интерпретирует полученные байты как текст в определенной кодировке.
  2. responseBody — возвращает сырые бинарные данные в виде массива байтов (SafeArray).

Важный момент: GZIP-архив — это двоичный файл. При обращении к responseText объект пытается найти символы, соответствующие байтам архива, что полностью разрушает его структуру. Поэтому для работы со сжатыми данными мы всегда должны использовать responseBody.

Решение 1: Использование ADODB.Stream для сохранения архива

Рассмотрим по шагам процесс получения данных и сохранения их в промежуточный файл. Для записи бинарного потока на диск в операционных системах Windows идеально подходит COM-объект ADODB.Stream. Этот метод особенно актуален для старых версий платформы (например, 1С 8.2), где работа с двоичными данными была ограничена.

Разберем пример кода для получения и сохранения сжатого файла:


// Инициализируем HTTP-запрос
WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
WinHttp.Open("GET", АдресФайлаВИнтернете, Ложь);
WinHttp.Send();

Если WinHttp.Status = 200 Тогда
    // Создаем поток для работы с бинарными данными
    Stream = Новый COMОбъект("ADODB.Stream");
    
    // Устанавливаем тип данных: 1 - бинарный
    Stream.Type = 1;
    // Устанавливаем режим доступа: 3 - чтение и запись
    Stream.Mode = 3;
    
    Stream.Open();
    // Записываем тело ответа (именно ResponseBody!) в поток
    Stream.Write(WinHttp.ResponseBody); 
    
    // Сохраняем во временный файл с расширением .gz или .zip
    ИмяПромежуточногоФайла = "C:\temp\data.gz";
    Stream.SaveToFile(ИмяПромежуточногоФайла, 2); // 2 - перезаписать, если существует
    
    Stream.Close();
    Stream = Неопределено;
    Сообщить("Файл успешно сохранен.");
Иначе
    Сообщить("Ошибка HTTP: " + WinHttp.Status + " " + WinHttp.StatusText);
КонецЕсли;

Решение 2: Распаковка с помощью внешних утилит (7-Zip или WinRAR)

После того как мы сохранили файл на диск, его необходимо распаковать. Если ваша версия платформы 1С не поддерживает нативный метод ЧтениеZipФайла для работы с GZIP (или файл не имеет структуры стандартного ZIP-архива), самым простым и надежным способом будет вызов внешнего архиватора.

Проанализируем ситуацию с использованием популярного архиватора 7-Zip. Рассмотрим пример команды для распаковки через метод ЗапуститьПриложение:


ПутьКАрхиватору = "C:\Program Files\7-Zip\7z.exe";
ФайлАрхива = "C:\temp\data.gz";
ПапкаНазначения = "C:\temp\unpacked\";

// Формируем командную строку: e - извлечь, -aoa - перезаписывать без вопросов
Команда = """" + ПутьКАрхиватору + """ e """ + ФайлАрхива + """ -aoa -o""" + ПапкаНазначения + """";

ЗапуститьПриложение(Команда, , Истина); // Истина - ждать завершения

Если на компьютере установлен WinRAR, принцип остается тем же, меняются только ключи командной строки:


// x - извлечь с сохранением структуры путей
КомандаWinRAR = """" + "C:\Program Files\WinRAR\WinRAR.exe" + """ x " + ФайлАрхива + " *.* " + ПапкаНазначения;
ЗапуститьПриложение(КомандаWinRAR, , Истина);

Совет: Если архиватор не распознает расширение .gz, попробуйте программно переименовать файл в .zip перед распаковкой. Часто серверы отдают поток данных без заголовков контейнера, и архиваторы лучше справляются с ними при стандартном расширении.

Решение 3: Управление заголовками Accept-Encoding

Иногда проблему проще предотвратить, чем решать. Мы можем "попросить" сервер не сжимать данные. Для этого используется HTTP-заголовок Accept-Encoding. Рассмотрим, как изменить запрос, чтобы получить чистый текст:


XMLHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
XMLHttp.Open("GET", АдресФайлаВИнтернете, Ложь);

// Указываем серверу, что нам нужны данные без сжатия
XMLHttp.SetRequestHeader("Accept-Encoding", "identity");

XMLHttp.Send();
Отв = XMLHttp.responseText; // Теперь здесь должен быть читаемый текст

Однако стоит учитывать, что некоторые серверы игнорируют этот заголовок и всегда присылают сжатый контент для оптимизации производительности. В таком случае придется возвращаться к методам распаковки. Для интерактивной проверки реакции сервера на заголовки и анализа ответа подойдёт консоль HTTP-запросов для управляемых форм.

Нюансы формата GZIP и "магические числа"

При автоматизации процесса полезно знать, как определить, действительно ли пришел сжатый файл. Каждый GZIP-файл начинается с так называемых "магических чисел" — последовательности байтов 1F 8B 08. Если вы анализируете первые байты ResponseBody и видите эти значения, значит, перед вами точно поток GZIP.

Если же сервер присылает данные с алгоритмом Deflate (который является "ядром" GZIP, но без заголовков), 1С может распаковать их штатными средствами в версиях 8.3.10+, используя объект ЧтениеДанных и буферы. Для старых платформ вызов внешнего 7z.exe остается самым универсальным решением. При необходимости можно использовать пример обработки сжатого по HTTP ответа прямо в 1С.

Итоги

Мы проанализировали основные способы работы со сжатыми ответами сервера. Подведем итог алгоритму наших действий:

  1. Используем WinHttp.WinHttpRequest.5.1 для отправки запроса.
  2. Забираем данные через свойство responseBody.
  3. С помощью ADODB.Stream сохраняем массив байтов в файл на диске.
  4. Вызываем внешний архиватор (7-Zip или WinRAR) через командную строку для извлечения содержимого.
  5. Читаем распакованный текстовый файл стандартными средствами 1С (ТекстовыйДокумент или ЧтениеТекста).

Такой подход гарантирует стабильную работу даже на устаревших версиях платформы 1С и позволяет обрабатывать файлы любого объема.

← На главную