Как скачать файл по HTTP-запросу в 1С: передача параметров, кодирование кириллицы и разбор ошибок

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

Интеграция систем 1С с внешними веб-сервисами — одна из самых частых задач современного разработчика. Простой перенос логики из других языков программирования (например, C# с его удобным WebClient.DownloadFile) в среду 1С часто вызывает трудности. Разработчики сталкиваются со скрытыми нюансами протокола HTTP: некорректной передачей параметров, искажением кириллических символов или получением пустых HTML-страниц вместо ожидаемых файлов.

В этой статье мы подробно разберем, как правильно реализовать скачивание файлов с веб-сервиса с помощью встроенных объектов 1С, исправим типичные архитектурные ошибки и научимся обрабатывать ответы сервера на профессиональном уровне.

В чем заключалась проблема: разбор типичных ошибок

Проанализируем ситуацию, описанную в теме. Разработчик пытался отправить запрос к веб-серверу Oracle HTTP Server (выступающему шлюзом к базе данных через модуль mod_plsql) для генерации и скачивания отчета в формате XLS. На пути к работающему коду возникло несколько критических преград:

  1. Передача параметров в заголовках запроса вместо тела или URL. Попытка использовать метод HTTPЗапрос.Заголовки.Вставить() для передачи параметров p_com и p_reestr_format привела к тому, что сервер их проигнорировал и вернул дефолтную страницу настроек.
  2. Проблема с кодированием кириллицы. Отправка русскоязычного параметра «Пуск» ломала логику бэкенда. Разработчикам пришлось переделывать сервис под латинское слово «Start», хотя проблему можно было решить исключительно средствами 1С.
  3. Жесткое кодирование имени файла. Имя сохраняемого файла прописывалось вручную (test.xls), несмотря на то, что сервер отправлял точное и красивое русское имя файла в заголовках ответа.
  4. Миф о невозможности работы со сжатием gzip. Опасения по поводу невозможности прочитать сжатые данные в 1С заставляли отказываться от эффективной передачи данных.

Давайте пошагово рассмотрим, как правильно решить каждую из этих задач.

Решение 1. Правильная отправка параметров через GET-запрос

Если веб-сервис принимает параметры методом GET, они должны быть частью адресной строки (ресурса), а не HTTP-заголовков. Заголовки HTTP предназначены для передачи служебной информации (тип контента, авторизация, кодировка), в то время как параметры запроса идентифицируют запрашиваемые данные.

Рассмотрим пример правильного формирования GET-запроса в 1С с динамической сборкой параметров:


// 1. Создаем HTTP-соединение с сервером
Сервер = "dezvgr2";
Соединение = Новый HTTPСоединение(Сервер);

// 2. Формируем параметры запроса. Обязательно кодируем кириллицу!
ПараметрДействие = КодироватьСтроку("Пуск", СпособКодированияСтроки.КодировкаURL, "windows-1251");

ПараметрыЗапроса = "rep_user=TVERETINA"
                 + "&p_com=30274"
                 + "&p_reestr_format=xls"
                 + "&p_action=" + ПараметрДействие;

// 3. Собираем полный адрес ресурса
АдресРесурса = "/pls/info/REESTR_PERSONS_TO_1C.run?" + ПараметрыЗапроса;

// 4. Инициализируем запрос
Запрос = Новый HTTPЗапрос(АдресРесурса);

// Добавляем стандартные заголовки для имитации браузера (при необходимости)
Запрос.Заголовки.Вставить("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
Запрос.Заголовки.Вставить("Accept", "application/vnd.ms-excel, */*");

// 5. Отправляем запрос
Ответ = Соединение.Получить(Запрос);

// 6. Проверяем статус ответа
Если Ответ.КодСостояния = 200 Тогда
    ДвоичныеДанные = Ответ.ПолучитьТелоКакДвоичныеДанные();
    ДвоичныеДанные.Записать("C:\temp\reestr.xls");
    Сообщить("Файл успешно сохранен!");
Иначе
    Сообщить("Ошибка сервера: " + Ответ.КодСостояния);
КонецЕсли;

Обратите внимание: использование функции КодироватьСтроку() с указанием кодировки windows-1251 (или UTF-8 в зависимости от настроек вашего сервера) полностью решает проблему с передачей русских букв. Сервер корректно примет параметр «Пуск» без необходимости переписывать код бэкенда на «Start».

Решение 2. Передача параметров через POST-запрос (application/x-www-form-urlencoded)

Если сервер ожидает POST-запрос, параметры нельзя передавать в строке URL. Их необходимо поместить в тело запроса, предварительно сообщив серверу тип передаваемого контента с помощью заголовка Content-Type.

Разберем, как реализовать POST-запрос в 1С:


Соединение = Новый HTTPСоединение("dezvgr2");

// Указываем только путь к скрипту без параметров в URL
Запрос = Новый HTTPЗапрос("/pls/info/REESTR_PERSONS_TO_1C.run");

// Устанавливаем заголовок, сообщающий, что данные передаются как форма веб-страницы
Запрос.Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");
Запрос.Заголовки.Вставить("User-Agent", "Mozilla/5.0");

// Формируем тело запроса
ПараметрДействие = КодироватьСтроку("Пуск", СпособКодированияСтроки.КодировкаURL, "windows-1251");
СтрокаПараметров = "rep_user=TVERETINA&p_com=30274&p_reestr_format=xls&p_action=" + ПараметрДействие;

// Записываем строку параметров в тело запроса в кодировке сервера
Запрос.УстановитьТелоИзСтроки(СтрокаПараметров, "windows-1251", ИспользованиеByteOrderMark.НеИспользовать);

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

Если Ответ.КодСостояния = 200 Тогда
    ДвоичныеДанные = Ответ.ПолучитьТелоКакДвоичныеДанные();
    ДвоичныеДанные.Записать("C:\temp\reestr.xls");
    Сообщить("Файл успешно получен через POST!");
Иначе
    Сообщить("Ошибка при POST-запросе: " + Ответ.КодСостояния);
КонецЕсли;

Решение 3. Автоматическое определение имени файла из заголовков ответа

В логах веб-сервера из обсуждения четко видно, что сервер отправляет заголовок:

Content-Disposition: attachment; filename="%D0%A1%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D1%8F...xls"

Этот заголовок содержит оригинальное имя файла, сгенерированное системой (например, "Сведения о проживающих...xls"), закодированное в формате URL-Encode. Вместо того чтобы заставлять пользователя сохранять все файлы под именем test.xls, мы можем динамически вытащить имя из ответа сервера.

Давайте реализуем алгоритм разбора заголовков:


Ответ = Соединение.Получить(Запрос);

Если Ответ.КодСостояния = 200 Тогда
    
    ИмяФайлаДляСохранения = "default.xls"; // Имя по умолчанию
    
    // Получаем значение заголовка Content-Disposition
    ЗначениеЗаголовка = Ответ.Заголовки.Получить("Content-Disposition");
    
    Если ЗначениеЗаголовка <> Неопределено Тогда
        // Ищем подстроку filename="..." с помощью регулярного выражения или строковых функций
        ПозицияИмени = Найти(ЗначениеЗаголовка, "filename=");
        Если ПозицияИмени > 0 Тогда
            ЗакодированноеИмя = Сред(ЗначениеЗаголовка, ПозицияИмени + 9);
            // Очищаем от кавычек, если они есть
            ЗакодированноеИмя = СтрЗаменить(ЗакодированноеИмя, """", "");
            
            // Раскодируем имя файла из URL-формата (UTF-8 или Win-1251)
            ИмяФайлаДляСохранения = РаскодироватьСтроку(ЗакодированноеИмя, СпособКодированияСтроки.КодировкаURL, "UTF-8");
        КонецЕсли;
    КонецЕсли;
    
    // Сохраняем файл на диск с оригинальным именем
    ДвоичныеДанные = Ответ.ПолучитьТелоКакДвоичныеДанные();
    ПолныйПуть = "C:\temp\" + ИмяФайлаДляСохранения;
    ДвоичныеДанные.Записать(ПолныйПуть);
    
    Сообщить("Файл успешно сохранен как: " + ПолныйПуть);
КонецЕсли;

Развеиваем мифы: работа со сжатием (gzip / deflate)

В обсуждении прозвучала мысль, что заголовок Accept-Encoding: gzip, deflate использовать нельзя, так как «ответ потом не прочитаете». Это утверждение давно не соответствует действительности.

Начиная с версии платформы 1С:Предприятие 8.3.6, объект HTTPСоединение осуществляет автоматическую распаковку сжатых данных «на лету». Если веб-сервер поддерживает gzip и сжимает возвращаемый XLS-файл (что уменьшает его размер в 5–10 раз), 1С самостоятельно примет архив, распакует его в оперативной памяти и вернет в метод ПолучитьТелоКакДвоичныеДанные() уже готовый, распакованный XLS-документ.

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

Запрос.Заголовки.Вставить("Accept-Encoding", "gzip, deflate");

Итог совместной работы

Мы проанализировали логи сетевого обмена, разобрали архитектуру HTTP-запросов и написали надежный, отказоустойчивый код на стороне 1С. Теперь наше решение умеет:

← На главную