Загрузка файла из интернета в 1С:Предприятие 8.3 через HTTPСоединение и БСП

· 10 мин

Содержание

Чтобы скачать файл по ссылке в 1С, разберите адрес на сервер и путь, создайте HTTPСоединение, отправьте HTTPЗапрос методом Получить(Запрос, ИмяВыходногоФайла) и проверьте КодСостояния ответа. Если код 200, файл уже лежит на диске. В типовых конфигурациях на БСП то же самое делает одна строка: ПолучениеФайловИзИнтернета.СкачатьФайлНаСервере(URL).

Обычно задача звучит так: поставщик прислал ссылку на прайс, банк отдаёт выписку по адресу, сервис возвращает PDF. Нужно забрать файл в базу без ручного «сохранить как». Ниже рабочий код для платформы 8.3, разбор HTTPS и перенаправлений, приёмы для больших файлов и ошибки, которые встречаются чаще других.

Что подготовить до написания кода

Сначала решите, где будет выполняться загрузка. От этого зависят сеть, права и способ отдать файл пользователю.

Где выполняетсяКогда подходитНа что смотреть
🖥️ На сервере 1СРегламентные задания, обмены, клиент-серверная базаСеть и прокси у учётной записи службы сервера 1С, а не у пользователя
💻 На клиенте (тонкий, толстый)Файл нужен только этому пользователюВ веб-клиенте HTTPСоединение недоступно
📁 Файловая базаНебольшая организацияКод «на сервере» фактически выполняется на компьютере пользователя

Для серверного варианта проверьте, что с машины, где работает служба 1С, адрес открывается. Служба обычно запущена от отдельного пользователя (часто USR1CV8). У него может не быть прокси-настроек, которые прописаны в браузере администратора. Самая частая загадка «у меня в браузере качается, а из 1С нет» объясняется именно этим.

Ещё три вещи до старта:

  • 🔗 Ссылка прямая. Ссылка на страницу «скачать» у облачных дисков отдаёт HTML, а не файл. Нужна ссылка, по которой браузер сразу начинает загрузку.
  • 🔐 Авторизация. Если ресурс требует логин, заранее узнайте её вид: базовая (логин и пароль), токен в заголовке или cookie после входа.
  • 📦 Размер. Для файлов от сотни мегабайт сразу планируйте запись на диск, а не в память.

Как платформа работает с HTTP: соединение, запрос, ответ

Загрузка собирается из трёх объектов встроенного языка.

  1. HTTPСоединение — соединение с одним сервером. Конструктор принимает хост, порт, пользователя, пароль, прокси, таймаут в секундах и объект защищённого соединения. Путь к файлу сюда не передают, только адрес сервера.
  2. HTTPЗапрос — путь на сервере вместе со строкой параметров (/files/price.xlsx?id=15) и соответствие заголовков.
  3. HTTPОтвет — результат. Из него берут КодСостояния, Заголовки и тело.

У метода Получить два режима. Без второго параметра тело ответа остаётся в памяти, его забирают через ПолучитьТелоКакДвоичныеДанные(). Со вторым параметром ИмяВыходногоФайла платформа сама пишет тело в файл по мере получения.

Для HTTPS нужен объект ЗащищенноеСоединениеOpenSSL. Если создать его без параметров, соединение шифруется, но сертификат сервера не проверяется. Правильнее передать хранилище корневых сертификатов: Новый СертификатыУдостоверяющихЦентровОС в актуальных версиях платформы или Новый СертификатыУдостоверяющихЦентровWindows на серверах под Windows.

Порт можно не указывать: при наличии защищённого соединения платформа подставит 443, без него 80. Явный порт нужен, только если он нестандартный и записан в адресе после двоеточия.

Пошаговая инструкция: скачиваем файл по ссылке кодом

Код ниже работает в любой конфигурации, БСП не нужна. Поместите его в общий модуль с флажком «Сервер» (например, ЗагрузкаФайлов), тогда директивы компиляции не понадобятся.

Шаг 1. Разобрать URL на части

Функция РазобратьURL(Знач URL) Экспорт

	Результат = Новый Структура("Схема, Хост, Порт, Путь", "http", "", 0, "/");

	Позиция = СтрНайти(URL, "://");
	Если Позиция > 0 Тогда
		Результат.Схема = НРег(Лев(URL, Позиция - 1));
		URL = Сред(URL, Позиция + 3);
	КонецЕсли;

	Позиция = СтрНайти(URL, "/");
	Если Позиция > 0 Тогда
		ХостПорт = Лев(URL, Позиция - 1);
		Результат.Путь = Сред(URL, Позиция);
	Иначе
		ХостПорт = URL;
	КонецЕсли;

	Позиция = СтрНайти(ХостПорт, ":");
	Если Позиция > 0 Тогда
		Результат.Хост = Лев(ХостПорт, Позиция - 1);
		Результат.Порт = Число(Сред(ХостПорт, Позиция + 1));
	Иначе
		Результат.Хост = ХостПорт;
		Результат.Порт = ?(Результат.Схема = "https", 443, 80);
	КонецЕсли;

	Возврат Результат;

КонецФункции

Для адреса https://example.ru/upload/price.xlsx?v=2 получится схема https, хост example.ru, порт 443 и путь /upload/price.xlsx?v=2. В типовых конфигурациях вместо своей функции можно взять ОбщегоНазначенияКлиентСервер.СтруктураURI(URL).

Шаг 2. Найти заголовок без учёта регистра

Сервер может прислать Location, а может location. Соответствие в 1С чувствительно к регистру ключа, поэтому ищем перебором:

Функция ЗначениеЗаголовка(Ответ, Имя)

	Для Каждого КлючИЗначение Из Ответ.Заголовки Цикл
		Если НРег(КлючИЗначение.Ключ) = НРег(Имя) Тогда
			Возврат КлючИЗначение.Значение;
		КонецЕсли;
	КонецЦикла;

	Возврат "";

КонецФункции

Шаг 3. Скачать файл с учётом перенаправлений

HTTPСоединение не переходит по редиректам само. Ответ 301 или 302 придёт как есть, а в файле окажется пустая или служебная страница. Поэтому перенаправления обрабатываем вручную, с ограничением на пять переходов:

Функция СкачатьФайлПоСсылке(Знач URL, Знач Расширение = "") Экспорт

	ИмяФайла = ПолучитьИмяВременногоФайла(Расширение);
	КодыПеренаправления = СтрРазделить("301,302,303,307,308", ",");

	Для НомерПерехода = 1 По 5 Цикл

		Части = РазобратьURL(URL);

		Защищенное = Неопределено;
		Если Части.Схема = "https" Тогда
			Защищенное = Новый ЗащищенноеСоединениеOpenSSL(, Новый СертификатыУдостоверяющихЦентровОС);
		КонецЕсли;

		Соединение = Новый HTTPСоединение(Части.Хост, Части.Порт, , , , 60, Защищенное);

		Заголовки = Новый Соответствие;
		Заголовки.Вставить("User-Agent", "1C-Enterprise");
		Запрос = Новый HTTPЗапрос(Части.Путь, Заголовки);

		Ответ = Соединение.Получить(Запрос, ИмяФайла);
		Код = Формат(Ответ.КодСостояния, "ЧГ=0");

		Если Ответ.КодСостояния = 200 Тогда
			Возврат ИмяФайла;
		ИначеЕсли КодыПеренаправления.Найти(Код) <> Неопределено Тогда
			НовыйАдрес = ЗначениеЗаголовка(Ответ, "Location");
			Если ПустаяСтрока(НовыйАдрес) Тогда
				Прервать;
			КонецЕсли;
			Если Лев(НовыйАдрес, 1) = "/" Тогда
				НовыйАдрес = Части.Схема + "://" + Части.Хост + ":"
					+ Формат(Части.Порт, "ЧГ=0") + НовыйАдрес;
			КонецЕсли;
			URL = НовыйАдрес;
		Иначе
			УдалитьФайлы(ИмяФайла);
			ВызватьИсключение "Сервер вернул код " + Код + " по адресу " + URL;
		КонецЕсли;

	КонецЦикла;

	УдалитьФайлы(ИмяФайла);
	ВызватьИсключение "Не удалось скачать файл: перенаправления не привели к файлу";

КонецФункции

Функция возвращает полный путь к временному файлу на сервере. Удалить его после использования — забота вызывающего кода.

Шаг 4. Отдать файл пользователю

Пользователю файл с сервера передают через временное хранилище. В модуле формы:

&НаСервере
Функция АдресСкачанногоФайла(Знач URL)

	ИмяФайла = ЗагрузкаФайлов.СкачатьФайлПоСсылке(URL, "pdf");
	Адрес = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ИмяФайла), УникальныйИдентификатор);
	УдалитьФайлы(ИмяФайла);
	Возврат Адрес;

КонецФункции

&НаКлиенте
Процедура СкачатьПоСсылке(Команда)

	Адрес = АдресСкачанногоФайла(СсылкаНаФайл);
	ФайловаяСистемаКлиент.СохранитьФайл(Неопределено, Адрес, "document.pdf");

КонецПроцедуры

Здесь СсылкаНаФайл — реквизит формы со строкой адреса. ФайловаяСистемаКлиент есть в конфигурациях на БСП. Без БСП используйте платформенный НачатьПолучениеФайлаССервера (платформа 8.3.18 и выше).

Скачивание файлов в типовой конфигурации на БСП

В Бухгалтерии 3.0, ЗУП 3.1, УТ 11 и других конфигурациях на БСП свой HTTP-код писать не обязательно. Подсистема «Получение файлов из интернета» уже умеет редиректы, прокси из настроек программы и защищённое соединение.

ПараметрыПолучения = ПолучениеФайловИзИнтернетаКлиентСервер.ПараметрыПолученияФайла();
ПараметрыПолучения.Таймаут = 60;

Результат = ПолучениеФайловИзИнтернета.СкачатьФайлНаСервере(URL, ПараметрыПолучения);

Если Не Результат.Статус Тогда
	ВызватьИсключение Результат.СообщениеОбОшибке;
КонецЕсли;

ИмяФайла = Результат.Путь;

В параметрах получения также задают заголовки, логин и пароль, путь для сохранения. Состав полей смотрите прямо в функции ПараметрыПолученияФайла в конфигураторе: он меняется от версии БСП.

Если файл нужно прикрепить к документу или справочнику, кладите его в подсистему «Работа с файлами», а не храните путь к временному файлу. Скачанный файл помещают во временное хранилище и передают в РаботаСФайлами.ДобавитьФайл вместе со структурой из РаботаСФайлами.ПараметрыДобавленияФайла(). В ней указывают владельца (ссылку на объект), имя без расширения и расширение. Файл появится в списке присоединённых файлов объекта, как если бы его перетащили мышью.

Не вносите эти функции в модули типовой конфигурации напрямую. Пишите их во внешней обработке или в расширении конфигурации, иначе при следующем обновлении придётся сравнивать и объединять изменения вручную.

Большие файлы: пишем сразу на диск

Для архивов, выгрузок и видео главное правило одно: не держать тело ответа в памяти. Вариант Ответ.ПолучитьТелоКакДвоичныеДанные() грузит весь файл в оперативную память рабочего процесса. На файле в 1–2 ГБ это заканчивается ошибкой нехватки памяти или заметным торможением сервера у всех пользователей.

Что делать:

  1. Передавайте в Получить второй параметр с именем файла, как в коде выше. Платформа пишет данные на диск частями.
  2. Увеличьте таймаут. 60 секунд хватает для прайса, но не для архива на 800 МБ по медленному каналу. Ставьте 300–600 секунд или считайте от ожидаемой скорости.
  3. Узнайте размер заранее. Метод Соединение.ПолучитьЗаголовки(Запрос) отправляет запрос HEAD и возвращает только заголовки. Значение Content-Length подскажет, хватит ли места и стоит ли вообще качать.
  4. Не гоняйте гигабайты через временное хранилище к клиенту. Если файл нужен для обработки на сервере, обработайте его там же и отдайте пользователю результат.
ОтветЗаголовки = Соединение.ПолучитьЗаголовки(Запрос);
ДлинаСтрокой = ЗначениеЗаголовка(ОтветЗаголовки, "Content-Length");
Если ЗначениеЗаполнено(ДлинаСтрокой)
	И Число(ДлинаСтрокой) > 200 * 1024 * 1024 Тогда
	ВызватьИсключение "Файл больше 200 МБ, загрузка отменена";
КонецЕсли;

Не все серверы присылают Content-Length, особенно при динамической отдаче. Поэтому после загрузки дополнительно проверьте фактический размер: Новый Файл(ИмяФайла).Размер().

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

Безопасность и проверка скачанного файла

Код 200 ещё не значит, что пришёл нужный файл. Сервер мог вернуть страницу входа, сообщение «файл не найден» в HTML или обрезанный архив. Перед тем как разбирать файл, проверьте его.

  • 🧾 Тип содержимого. Заголовок Content-Type для HTML-страницы будет text/html. Для PDF ждите application/pdf, для XLSX — тип с spreadsheetml.
  • 🔢 Первые байты. PDF начинается с символов %PDF (байты 37, 80, 68, 70). Файлы XLSX, DOCX и ZIP начинаются с PK (байты 80, 75).
  • 📏 Размер. Пустой файл или файл в пару килобайт вместо ожидаемых мегабайт — повод остановиться.
  • #️⃣ Контрольная сумма. Если поставщик публикует хеш, сверьте его через ХешированиеДанных с ХешФункция.SHA256.

Проверка сигнатуры PDF:

Функция ЭтоPDF(ИмяФайла)

	Чтение = Новый ЧтениеДанных(ИмяФайла);
	Сигнатура = Новый Массив;
	Для Сч = 1 По 4 Цикл
		Сигнатура.Добавить(Чтение.ПрочитатьБайт());
	КонецЦикла;
	Чтение.Закрыть();

	Возврат Сигнатура[0] = 37 И Сигнатура[1] = 80
		И Сигнатура[2] = 68 И Сигнатура[3] = 70;

КонецФункции

Отдельно про адреса, которые вводит пользователь. Если в форме есть поле «ссылка», через него можно заставить сервер 1С обращаться к внутренним ресурсам сети: http://192.168.1.10/..., консолям администрирования и т.п. Защита простая:

  • держите список разрешённых доменов и сверяйте с ним хост после разбора URL;
  • допускайте только схемы http и https;
  • не запускайте скачанные .exe, .bat, .js и не открывайте их программно;
  • логин и пароль к ресурсу храните в безопасном хранилище БСП (ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище), а не в тексте модуля.

Внешняя обработка, подключённая в безопасном режиме, не получит доступ к интернету без разрешения. В типовых конфигурациях с включёнными профилями безопасности программа сама запросит разрешение на интернет-ресурс при регистрации обработки.

Ошибки при загрузке файла по ссылке и как их снять

Платформа передаёт текст ошибки сетевой библиотеки, поэтому сообщения часто на английском и начинаются со слов Ошибка работы с Интернет:. Выберите свой случай:

Диагностика: выберите симптом

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

Частые вопросы

Можно ли скачать файл по ссылке без программирования?
Нет, встроенной команды «загрузить по ссылке» в типовых списках файлов нет. Сохраните файл через браузер и прикрепите его к объекту обычным способом. Открыть ссылку в браузере из 1С можно методом ПерейтиПоНавигационнойСсылке.
Почему в веб-клиенте код не работает?
В веб-клиенте объект HTTPСоединение недоступен. Выполняйте загрузку на сервере и передавайте пользователю результат через временное хранилище.
Как скачать файл, если нужен POST-запрос?
Сформируйте HTTPЗапрос, задайте тело методом УстановитьТелоИзСтроки и вызовите Соединение.ОтправитьДляОбработки(Запрос, ИмяВыходногоФайла). Второй параметр так же пишет ответ в файл.
Где лежит временный файл на сервере?
ПолучитьИмяВременногоФайла создаёт имя в каталоге временных файлов пользователя, от которого работает процесс сервера 1С. Удаляйте файл сразу после обработки, иначе каталог быстро разрастается.
Можно ли качать файлы по расписанию?
Да. Вызовите функцию загрузки из процедуры регламентного задания в серверном общем модуле. В файловой базе регламентные задания выполняются, только пока база открыта у кого-то из пользователей.