При активном обмене данными с веб-сервисами разработчики часто сталкиваются с ситуацией, когда сервер в целях экономии трафика возвращает ответ, сжатый алгоритмом GZIP. Если попытаться прочитать такой ответ стандартным методом responseText, мы получим нечитаемый набор символов ("кракозябры"). Это происходит потому, что сжатые данные являются бинарными, а попытка интерпретировать их как текст приводит к искажению структуры файла.
В этой статье мы подробно разберем, как корректно получить сжатые данные, сохранить их на диск и распаковать, используя возможности платформы 1С и системные компоненты Windows. Мы проанализируем несколько подходов: от управления заголовками запроса до использования внешних архиваторов.
Прежде всего, выясним причину, по которой обычный метод чтения текста не работает. Когда мы используем объект WinHttp.WinHttpRequest.5.1, у нас есть два способа получить тело ответа:
responseText — интерпретирует полученные байты как текст в определенной кодировке.responseBody — возвращает сырые бинарные данные в виде массива байтов (SafeArray).Важный момент: GZIP-архив — это двоичный файл. При обращении к responseText объект пытается найти символы, соответствующие байтам архива, что полностью разрушает его структуру. Поэтому для работы со сжатыми данными мы всегда должны использовать responseBody.
Рассмотрим по шагам процесс получения данных и сохранения их в промежуточный файл. Для записи бинарного потока на диск в операционных системах 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);
КонецЕсли;
После того как мы сохранили файл на диск, его необходимо распаковать. Если ваша версия платформы 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 перед распаковкой. Часто серверы отдают поток данных без заголовков контейнера, и архиваторы лучше справляются с ними при стандартном расширении.
Иногда проблему проще предотвратить, чем решать. Мы можем "попросить" сервер не сжимать данные. Для этого используется HTTP-заголовок Accept-Encoding. Рассмотрим, как изменить запрос, чтобы получить чистый текст:
XMLHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
XMLHttp.Open("GET", АдресФайлаВИнтернете, Ложь);
// Указываем серверу, что нам нужны данные без сжатия
XMLHttp.SetRequestHeader("Accept-Encoding", "identity");
XMLHttp.Send();
Отв = XMLHttp.responseText; // Теперь здесь должен быть читаемый текст
Однако стоит учитывать, что некоторые серверы игнорируют этот заголовок и всегда присылают сжатый контент для оптимизации производительности. В таком случае придется возвращаться к методам распаковки. Для интерактивной проверки реакции сервера на заголовки и анализа ответа подойдёт консоль HTTP-запросов для управляемых форм.
При автоматизации процесса полезно знать, как определить, действительно ли пришел сжатый файл. Каждый GZIP-файл начинается с так называемых "магических чисел" — последовательности байтов 1F 8B 08. Если вы анализируете первые байты ResponseBody и видите эти значения, значит, перед вами точно поток GZIP.
Если же сервер присылает данные с алгоритмом Deflate (который является "ядром" GZIP, но без заголовков), 1С может распаковать их штатными средствами в версиях 8.3.10+, используя объект ЧтениеДанных и буферы. Для старых платформ вызов внешнего 7z.exe остается самым универсальным решением. При необходимости можно использовать пример обработки сжатого по HTTP ответа прямо в 1С.
Мы проанализировали основные способы работы со сжатыми ответами сервера. Подведем итог алгоритму наших действий:
WinHttp.WinHttpRequest.5.1 для отправки запроса.responseBody.ADODB.Stream сохраняем массив байтов в файл на диске.ТекстовыйДокумент или ЧтениеТекста).Такой подход гарантирует стабильную работу даже на устаревших версиях платформы 1С и позволяет обрабатывать файлы любого объема.