Интеграция систем 1С с внешними веб-сервисами — одна из самых частых задач современного разработчика. Простой перенос логики из других языков программирования (например, C# с его удобным WebClient.DownloadFile) в среду 1С часто вызывает трудности. Разработчики сталкиваются со скрытыми нюансами протокола HTTP: некорректной передачей параметров, искажением кириллических символов или получением пустых HTML-страниц вместо ожидаемых файлов.
В этой статье мы подробно разберем, как правильно реализовать скачивание файлов с веб-сервиса с помощью встроенных объектов 1С, исправим типичные архитектурные ошибки и научимся обрабатывать ответы сервера на профессиональном уровне.
Проанализируем ситуацию, описанную в теме. Разработчик пытался отправить запрос к веб-серверу Oracle HTTP Server (выступающему шлюзом к базе данных через модуль mod_plsql) для генерации и скачивания отчета в формате XLS. На пути к работающему коду возникло несколько критических преград:
HTTPЗапрос.Заголовки.Вставить() для передачи параметров p_com и p_reestr_format привела к тому, что сервер их проигнорировал и вернул дефолтную страницу настроек.test.xls), несмотря на то, что сервер отправлял точное и красивое русское имя файла в заголовках ответа.Давайте пошагово рассмотрим, как правильно решить каждую из этих задач.
Если веб-сервис принимает параметры методом 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».
Если сервер ожидает 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-запросе: " + Ответ.КодСостояния);
КонецЕсли;
В логах веб-сервера из обсуждения четко видно, что сервер отправляет заголовок:
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\" + ИмяФайлаДляСохранения;
ДвоичныеДанные.Записать(ПолныйПуть);
Сообщить("Файл успешно сохранен как: " + ПолныйПуть);
КонецЕсли;
В обсуждении прозвучала мысль, что заголовок Accept-Encoding: gzip, deflate использовать нельзя, так как «ответ потом не прочитаете». Это утверждение давно не соответствует действительности.
Начиная с версии платформы 1С:Предприятие 8.3.6, объект HTTPСоединение осуществляет автоматическую распаковку сжатых данных «на лету». Если веб-сервер поддерживает gzip и сжимает возвращаемый XLS-файл (что уменьшает его размер в 5–10 раз), 1С самостоятельно примет архив, распакует его в оперативной памяти и вернет в метод ПолучитьТелоКакДвоичныеДанные() уже готовый, распакованный XLS-документ.
Поэтому смело добавляйте заголовки сжатия, чтобы экономить трафик компании и ускорить работу ваших интеграций:
Запрос.Заголовки.Вставить("Accept-Encoding", "gzip, deflate");
Мы проанализировали логи сетевого обмена, разобрали архитектуру HTTP-запросов и написали надежный, отказоустойчивый код на стороне 1С. Теперь наше решение умеет:
GET, так и методом POST.