При интеграции систем 1С с внешними веб-ресурсами разработчики регулярно сталкиваются с задачей автоматической выгрузки и загрузки файлов. В процессе отправки запросов могут возникать ошибки: от статусов перенаправления 301 Moved Permanently и 302 Found до серверных кодов 503 Service Unavailable или аварийных остановок платформы из-за нехватки оперативной памяти. Разберем по шагам, почему возникают подобные проблемы при обращении к веб-серверам и как правильно организовать получение файлов любого объема встроенными средствами 1С:Предприятия.
Проанализируем типовую ситуацию, возникшую в обсуждении. При попытке скачать файл по прямому адресу вида http://guvm.mvd.ru/... веб-сервер возвращает код состояния 302 или 503. Происходит это по следующим причинам:
HTTP на защищенный HTTPS. В ответ на незащищенный запрос сервер отправляет статус 301 или 302 и заголовок ответа Location, содержащий новый полный URL-адрес ресурса./upload/file.ext), а сервер присылает абсолютный URL (начиная со схемы https://...), повторный запрос к исходному HTTP-соединению завершается ошибкой либо бесконечным циклом рекурсии.User-Agent, принимая программный запрос за атаку или нежелательного бота.Наиболее простое и надежное решение, позволяющее избежать промежуточных редиректов, — изначально формировать соединение по защищенному протоколу HTTPS. Рассмотрим правильную инициализацию объекта HTTPСоединение с явным указанием защищенного соединения ЗащищенноеСоединениеOpenSSL.
Обратите внимание: при скачивании объемных файлов (весом в сотни мегабайт) критически важно увеличить стандартный таймаут соединения (например, до 300–600 секунд), чтобы предотвратить разрыв сессии во время передачи данных.
&НаСервере
Процедура СкачатьФайлПоHTTPS()
СерверИсточника = "guvm.mvd.ru";
ПутьКФайлу = "/upload/expired-passports/list_of_expired_passports.csv.bz2";
ИмяФайлаНаДиске = "C:\list_of_expired_passports.csv.bz2";
// Создаем объект защищенного соединения
Защита = Новый ЗащищенноеСоединениеOpenSSL();
// Инициализируем соединение: хост, порт 443, таймаут 300 сек, защищенное соединение
Соединение = Новый HTTPСоединение(СерверИсточника, 443, , , , 300, Защита);
Запрос = Новый HTTPЗапрос(ПутьКФайлу);
// Заполняем заголовок User-Agent для прохождения фильтров защиты сервера
Запрос.Заголовки.Вставить("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
Ответ = Соединение.Получить(Запрос, ИмяФайлаНаДиске);
Если Ответ.КодСостояния >= 200 И Ответ.КодСостояния < 300 Тогда
// Файл успешно получен и сохранен на диске
Иначе
ВызватьИсключение "Ошибка загрузки: код состояния " + Ответ.КодСостояния;
КонецЕсли;
КонецПроцедуры
Если ссылка на файл поступает в динамическом виде и может вести как на HTTP, так и на HTTPS, алгоритм должен корректно отслеживать код перенаправления. Разберем логику: если сервер вернул код 301 или 302, мы извлекаем значение заголовка Location, заново разбираем полученный URL на схему, хост и относительный путь, а затем пересоздаем объект HTTPСоединение.
&НаСервереБезКонтекста
Функция СкачатьФайлСКонтролемРедиректа(Знач АдресРесурса, ИмяФайлаПриемника, СчетчикРедиректов = 0)
Если СчетчикРедиректов > 5 Тогда
ВызватьИсключение "Превышено максимальное число перенаправлений (редиректов).";
КонецЕсли;
// Разбираем входящий URL
СтруктураURL = РазделитьURL(АдресРесурса);
Защита = Неопределено;
Порт = СтруктураURL.Порт;
Если НРег(СтруктураURL.Протокол) = "https" Тогда
Защита = Новый ЗащищенноеСоединениеOpenSSL();
Если Порт = Неопределено Тогда
Порт = 443;
КонецЕсли;
Иначе
Если Порт = Неопределено Тогда
Порт = 80;
КонецЕсли;
КонецЕсли;
Соединение = Новый HTTPСоединение(СтруктураURL.ИмяСервера, Порт, , , , 300, Защита);
Запрос = Новый HTTPЗапрос(СтруктураURL.ПутьКФайлуНаСервере);
Запрос.Заголовки.Вставить("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
Ответ = Соединение.Получить(Запрос, ИмяФайлаПриемника);
// Обработка кодов перенаправления
Если Ответ.КодСостояния = 301 Или Ответ.КодСостояния = 302 Тогда
НовыйАдрес = Ответ.Заголовки["Location"];
Если ПустаяСтрока(НовыйАдрес) Тогда
НовыйАдрес = Ответ.Заголовки["location"];
КонецЕсли;
// Если вернулся относительный путь, дополняем схемой и хостом
Если Найти(НовыйАдрес, "://") = 0 Тогда
НовыйАдрес = СтруктураURL.Протокол + "://" + СтруктураURL.ИмяСервера + НовыйАдрес;
КонецЕсли;
Возврат СкачатьФайлСКонтролемРедиректа(НовыйАдрес, ИмяФайлаПриемника, СчетчикРедиректов + 1);
КонецЕсли;
Возврат Ответ;
КонецФункции
В платформе 1С:Предприятие метод КопироватьФайл поддерживает передачу интернет-адресов по протоколам HTTP и HTTPS напрямую. Это наиболее лаконичный способ для простых сценариев загрузки:
&НаСервере
Процедура ЗагрузитьЧерезКопирование()
АдресИсточника = "https://guvm.mvd.ru/upload/expired-passports/list_of_expired_passports.csv.bz2";
ИмяФайлаПриемника = "C:\temp\list_of_expired_passports.csv.bz2";
КопироватьФайл(АдресИсточника, ИмяФайлаПриемника);
КонецПроцедуры
Важное примечание: При вызове метода КопироватьФайл невозможно передать тонкие настройки таймаута, заголовки User-Agent или обработать специфические коды ответов сервера. Если ресурс защищен строгими фильтрами или файл передается медленно, надежнее использовать HTTPСоединение.
После успешной загрузки файла часто начинаются следующие технические сложности, особенно если речь идет о реестрах вроде списка недействительных паспортов:
ЧтениеZipФайла работает исключительно с архивами формата ZIP. Поддержка формата .bz2 во встроенном языке отсутствует. Для распаковки таких данных скачанный файл сохраняют на жесткий диск и распаковывают внешней консольной утилитой (например, 7-Zip) с помощью метода ЗапуститьПриложение.ТекстовыйДокумент.Прочитать() или ЧтениеТекста.Прочитать() — это приведет к переполнению памяти и падению рабочего процесса rphost. Считывание должно выполняться только построчно через метод ЧтениеТекста.ПрочитатьСтроку().COPY для PostgreSQL или BULK INSERT для MS SQL Server), либо использовать проверку единичных записей через внешние онлайн-сервисы по запросу.