Как получить и прочитать XML-файл через HTTP-запрос в 1С?

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

При интеграции 1С со сторонними веб-сервисами часто возникает задача скачивания файлов, например, электронных счетов-фактур в формате XML. На первый взгляд, процесс кажется простым: отправить запрос и получить ответ. Однако на практике разработчики сталкиваются с рядом проблем: тело ответа оказывается пустым, возвращается непонятный поток данных или сервер отвечает кодом 302. Давайте подробно разберем по шагам, как правильно настроить HTTP-запрос, обработать ответ и прочитать полученный XML-файл.

Анализ проблемы: пустой ответ и попытка чтения потока

Рассмотрим классическую ситуацию: мы обращаемся к HTTP-сервису, который должен вернуть файл XML. Мы используем объект HTTPСоединение, формируем HTTPЗапрос и выполняем метод Получить. Пытаемся извлечь тело ответа с помощью метода ПолучитьТелоКакСтроку, но получаем пустую строку. Если мы используем метод ПолучитьТелоКакПоток, платформа возвращает объект типа Поток, с которым непонятно, что делать дальше.

Проанализируем ситуацию: если метод возврата строки дает пустой результат, то, скорее всего, тело ответа действительно пустое. Чтение его как потока в данном случае не поможет. Выясним причину такого поведения веб-сервера.

Причина 1: Некорректная передача параметров авторизации

Многие современные API требуют обязательной передачи логина и пароля. Если передать эти параметры в строке адреса (GET-запрос) вида get_file.php?login=xxx&pass=xxx, сервер может отклонить запрос из соображений безопасности (так как URL-адреса часто логируются прокси-серверами) или просто не понять его.

Разберем решение этой проблемы. Нам необходимо использовать POST-запрос, передавая параметры авторизации в теле запроса, а не в URL. При этом важно указать правильный заголовок, сообщающий серверу формат передаваемых данных.

Посмотрим на пример рабочего кода, решающего данную задачу:


Сервер = "api.example.ru";
Адрес = "get_invoice.php";

// Создаем защищенное соединение
Соединение = Новый HTTPСоединение(Сервер,,,,,180, Новый ЗащищенноеСоединениеOpenSSL(Неопределено, Неопределено));

// Устанавливаем заголовки
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");

HTTPЗапрос = Новый HTTPЗапрос(Адрес, Заголовки);

// Передаем параметры авторизации в теле запроса
HTTPЗапрос.УстановитьТелоИзСтроки("&login=ВашЛогин&pass=ВашПароль");

// Выполняем POST-запрос
HTTPОтвет = Соединение.ОтправитьДляОбработки(HTTPЗапрос); 

// Получаем текст ответа
ТекстОтвета = HTTPОтвет.ПолучитьТелоКакСтроку();

Используя метод ОтправитьДляОбработки и заголовок Content-Type: application/x-www-form-urlencoded, мы корректно передаем данные на сервер и получаем содержимое нашего XML-файла в виде строки.

Причина 2: Обработка перенаправления (Код состояния 302)

Что делать, если мы все равно получаем пустой ответ? Проанализируем код состояния, который возвращает сервер в свойстве HTTPОтвет.КодСостояния. Если он равен 302 (Found), это означает, что сервер выполнил перенаправление.

В 1С объект HTTPСоединение не переходит по редиректам автоматически. Сервер говорит нам: "Документ не здесь, он по другому адресу", и этот новый адрес передается в заголовках ответа.

Разберем по шагам, как обработать такую ситуацию:

  1. Проверяем код ответа. Если он равен 302, нам нужно найти новый адрес.
  2. Обращаемся к коллекции HTTPОтвет.Заголовки и ищем заголовок Location.
  3. Извлекаем значение заголовка (например, index.php?file_id=123).
  4. Формируем новый HTTPЗапрос с этим адресом и повторяем получение данных.

Как прочитать XML напрямую из потока?

Если API возвращает очень большой XML-файл, считывать его целиком в память с помощью ПолучитьТелоКакСтроку нерационально, это может вызвать переполнение памяти. В таких случаях мы как раз и используем ПолучитьТелоКакПоток.

Рассмотрим, как прочитать полученный поток. В 1С объект ЧтениеXML умеет работать с потоками напрямую, без предварительного сохранения в файл или строку.


ПотокОтвета = HTTPОтвет.ПолучитьТелоКакПоток();

ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьПоток(ПотокОтвета);

Пока ЧтениеXML.Прочитать() Цикл
    // Обработка узлов XML
    Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
        ИмяУзла = ЧтениеXML.Имя;
        // Дальнейшая логика разбора
    КонецЕсли;
КонецЦикла;

ЧтениеXML.Закрыть();

Для работы с бинарными или произвольными потоками данных (начиная с платформы 8.3.9) также можно использовать удобный объект ЧтениеДанных, который позволяет вычитывать информацию по частям.

Сохранение полученного файла на диск

Если вам требуется не просто прочитать данные, а сохранить XML-файл на диск пользователя, у объекта HTTPСоединение в методе Получить есть второй параметр — путь к файлу.

Кроме того, если вы обращали внимание на работу браузера, при скачивании файла ему автоматически присваивается правильное имя. Сервер передает это имя в специальном заголовке Content-Disposition. Разберем, как мы можем это использовать:


// Получаем заголовок
ЗаголовокИмени = HTTPОтвет.Заголовки.Получить("Content-Disposition");

// Заголовок обычно имеет вид: attachment; filename="invoice_123.xml"
// Парсим строку, чтобы достать имя файла, и сохраняем
ИмяФайла = ИзвлечьИмяФайлаИзЗаголовка(ЗаголовокИмени); // Ваша кастомная функция парсинга
ПутьКФайлу = КаталогВременныхФайлов() + ИмяФайла;

// Сохраняем тело ответа в файл
HTTPОтвет.ЗаписатьТелоВФайл(ПутьКФайлу);

Важный момент: Если вы столкнулись со сложностями при отладке (например, не знаете, какие именно заголовки возвращает сервер), используйте объект ЗаписьЖурналаРегистрации. Записывайте в журнал в цикле все ключи и значения из коллекции HTTPОтвет.Заголовки. Это поможет вам увидеть реальный Content-Type, наличие Content-Encoding: gzip (сжатие) и другие параметры, скрытые от глаз без применения сторонних программ-снифферов.

← На главную