В процессе разработки в среде 1С:Предприятие 8 часто возникает необходимость автоматизировать получение данных из внешних источников: прайс-листов поставщиков, курсов валют, классификаторов или обновлений. Одной из наиболее распространенных задач является скачивание файла по ссылке. На первый взгляд задача кажется простой, но на практике программисты сталкиваются с "невидимыми" ссылками, защищенными соединениями (SSL), блокировками со стороны серверов и проблемами определения расширения файла. В этой статье мы подробно разберем все этапы реализации этой задачи, от поиска прямой ссылки до обработки ответов сервера.
Прежде чем писать код, необходимо убедиться, что у нас есть прямая ссылка на файл. Часто на сайтах ссылка ведет не на сам документ, а на скрипт-обработчик (например, download.php?id=123) или на промежуточную страницу. Если использовать такую ссылку в методе КопироватьФайл, программа может скачать HTML-код страницы вместо ожидаемого архива или таблицы Excel.
Для определения реального расположения файла выполним следующие шаги:
Это самый простой способ, который подходит для прямых публичных ссылок, не требующих авторизации или специальных заголовков. Рассмотрим пример кода:
ИмяФайлаИсточника = "https://example.com/files/price.xlsx";
ИмяФайлаПриемника = "C:\Temp\price.xlsx";
Попытка
КопироватьФайл(ИмяФайлаИсточника, ИмяФайлаПриемника);
Сообщить("Файл успешно скачан!");
Исключение
Сообщить("Ошибка при скачивании: " + ОписаниеОшибки());
КонецПопытки;
Важно помнить, что КопироватьФайл работает в синхронном режиме и блокирует поток выполнения до завершения операции. Если файл большой, интерфейс программы может "зависнуть".
Для более гибкого управления процессом скачивания (например, когда нужно работать с HTTPS, передавать заголовки или анализировать ошибки сервера) следует использовать объект HTTPСоединение. Проанализируем стандартную ситуацию скачивания файла с сайта Центрального Банка или любого другого ресурса.
// Определяем параметры сервера и путь к файлу
Сервер = "www.cbr.ru";
ПутьНаСервере = "/print.asp?file=/statistics/credit_statistics/refinancing_rates.htm";
// Указываем локальный путь для сохранения
ПутьКЛокальномуФайлу = КаталогВременныхФайлов() + "rates.htm";
// Создаем соединение
НТТР = Новый HTTPСоединение(Сервер);
Попытка
// Выполняем получение файла
НТТР.Получить(ПутьНаСервере, ПутьКЛокальномуФайлу);
ВходящийФайл = Новый Файл(ПутьКЛокальномуФайлу);
Если ВходящийФайл.Существует() Тогда
Сообщить("Файл получен, размер: " + ВходящийФайл.Размер());
КонецЕсли;
Исключение
Сообщить("Не удалось соединиться с сервером");
КонецПопытки;
Современные сайты практически повсеместно используют протокол HTTPS. В 1С для работы с защищенным соединением необходимо использовать объект ЗащищенноеСоединениеOpenSSL. Рассмотрим пример для скачивания XML-прайса с защищенного ресурса:
ИнтернетАдрес = "www.example-shop.com";
ИмяФайлаНаСервере = "/upload/price.xml";
ЛокальныйПуть = "C:\Downloads\price.xml";
// Инициализируем защищенное соединение
// Используем стандартные настройки сертификатов ОС
SSL = Новый ЗащищенноеСоединениеOpenSSL();
// Создаем соединение на порту 443
Соединение = Новый HTTPСоединение(ИнтернетАдрес, 443, , , , , SSL);
// Формируем запрос
Запрос = Новый HTTPЗапрос(ИмяФайлаНаСервере);
Попытка
Ответ = Соединение.Получить(Запрос, ЛокальныйПуть);
// Проверяем код состояния (200 - успех)
Если Ответ.КодСостояния = 200 Тогда
Сообщить("Загрузка завершена успешно");
Иначе
Сообщить("Сервер вернул ошибку: " + Ответ.КодСостояния);
КонецЕсли;
Исключение
Сообщить("Произошла сетевая ошибка при обращении к " + ИнтернетАдрес);
КонецПопытки;
Если после скачивания вы обнаружили, что файл весит всего 1 Кб и не открывается, скорее всего, сервер заблокировал запрос от 1С. Многие серверы проверяют заголовок User-Agent, чтобы отсекать автоматических ботов. Если этот заголовок не заполнен, сервер может отдать страницу с ошибкой (например, "403 Forbidden") вместо файла.
Разберем, как имитировать запрос от обычного браузера:
Запрос = Новый HTTPЗапрос(ИмяФайлаНаСервере);
// Устанавливаем заголовок, имитирующий браузер Chrome
Запрос.Заголовки.Вставить("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
Ответ = Соединение.Получить(Запрос, ЛокальныйПуть);
Также размер в 1 Кб может указывать на то, что скачанный файл является текстовым сообщением об ошибке. Попробуйте открыть такой файл обычным "Блокнотом" (Notepad++) — часто внутри содержится текст ошибки в формате HTML или JSON, который поможет понять причину отказа.
Бывают ситуации, когда ссылка не содержит расширения (например, api/get_report?id=500). В этом случае мы не знаем заранее, скачивается ли .zip, .xlsx или .pdf. Выясним, как получить эту информацию программно.
Для этого необходимо проанализировать заголовки HTTP-ответа, которые возвращает сервер. Нас интересуют два заголовка: Content-Type (тип контента) и Content-Disposition (часто содержит имя файла).
Ответ = Соединение.Получить(Запрос); // Получаем данные в память без записи в файл
Если Ответ.КодСостояния = 200 Тогда
// 1. Попытаемся найти имя файла в заголовке Content-Disposition
ДанныеЗаголовка = Ответ.Заголовки.Получить("Content-Disposition");
// Пример значения: attachment; filename="report_2023.zip"
// 2. Или определим тип по Content-Type
ТипКонтента = Ответ.Заголовки.Получить("Content-Type");
// Если ТипКонтента = "application/zip", значит это архив.
// Сохраняем данные из тела ответа
ДвоичныеДанные = Ответ.ПолучитьТелоКакДвоичныеДанные();
ДвоичныеДанные.Записать(ПутьДляСохранения);
КонецЕсли;
Рассмотрим еще несколько важных моментов, которые помогут сделать ваш код более надежным:
HTTPСоединение всегда указывайте таймаут (например, 30 или 60 секунд). Это предотвратит бесконечное ожидание ответа от "зависшего" сервера.ИнтернетПрокси и передавайте его в конструктор соединения.HTTPЗапрос можно управлять кодировкой принимаемых данных.НачатьПолучение), чтобы не блокировать работу пользователя.Используя предложенные методы, вы сможете настроить стабильную загрузку файлов в 1С из любых внешних источников, обеспечив корректную обработку защищенных протоколов и различных типов данных.