В практике интеграции 1С с веб-ресурсами мы часто сталкиваемся с задачей загрузки изображений товаров или документов. В последнее время все чаще встречается формат WebP, который эффективно сжимает изображения. Однако, при попытке скачать такие файлы стандартными средствами платформы, мы можем получить файл, который не открывается ни одной программой просмотра, а система помечает его как "битый". Часто такие задачи возникают, когда требуется массовая выгрузка картинок номенклатуры в каталог или их загрузка из внешних источников. Давайте подробно разберем эту проблему, выясним истинную причину "поломки" файлов и рассмотрим надежные методы решения, позволяющие обойти защиту современных веб-серверов.
Ситуация обычно выглядит следующим образом: мы используем стандартный метод платформы, например, ПолучениеФайловИзИнтернета.СкачатьФайлВоВременноеХранилище или простой вызов КопироватьФайл.
Если мы скачиваем файлы форматов PNG или JPG, все проходит успешно. Но как только дело доходит до ссылки, оканчивающейся на .webp, сохраненный файл имеет ненулевой размер, но при попытке открытия мы получаем ошибку "Неверный формат" или "Файл поврежден". При этом, если вставить ту же самую ссылку в адресную строку браузера (Chrome, Firefox, Яндекс.Браузер), картинка открывается и скачивается корректно.
Первое, что нам необходимо сделать — это перестать относиться к файлу как к изображению. Давайте проанализируем содержимое того, что мы скачали. Для глубокого анализа низкоуровневой структуры данных может пригодиться универсальная библиотека для работы с двоичными данными, которая корректно работает на разных версиях платформы.
Диагностика:
Откройте "битый" файл с помощью Блокнота (Notepad). В 99% случаев вы увидите не бинарный код изображения, а текстовый код, начинающийся с тегов
или .
Это означает, что сервер не вернул нам картинку. Вместо этого он прислал HTML-страницу. Чаще всего внутри этого HTML содержится:
.webp.
User-Agent.
Mozilla/5.0 (Windows NT 10.0; Win64; x64).... Сервер понимает: "Это человек, отдаем картинку".1C+Enterprise/8.3. Сервер видит это и думает: "Это бот/скрипт, блокируем или просим пройти проверку".ПолучениеФайловИзИнтернета часто не позволяют гибко управлять этими параметрами. Поэтому нам придется спуститься на уровень ниже и использовать объект HTTPСоединение.
// Настраиваем параметры подключения
ИмяСервера = "example.com"; // Без http:// и https://
ПутьКФайлу = "/images/photo.webp"; // Путь от корня сайта
ЗащищенноеСоединение = Истина; // Обычно сейчас все на HTTPS
// Создаем соединение
Если ЗащищенноеСоединение Тогда
ОпределенияSSL = Новый ЗащищенноеСоединениеOpenSSL(Неопределено, Неопределено);
Соединение = Новый HTTPСоединение(ИмяСервера, 443, , , , , ОпределениеSSL);
Иначе
Соединение = Новый HTTPСоединение(ИмяСервера, 80);
КонецЕсли;
// Формируем заголовки, имитирующие браузер
Заголовки = Новый Соответствие;
// Важно: берем свежий User-Agent из своего браузера
Заголовки.Вставить("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
// Указываем, что мы готовы принять картинки
Заголовки.Вставить("Accept", "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8");
// Иногда требуется указать Referer (откуда мы пришли) - обычно главная страница сайта
Заголовки.Вставить("Referer", "https://" + ИмяСервера + "/");
// Создаем запрос
Запрос = Новый HTTPЗапрос(ПутьКФайлу, Заголовки);
// Выполняем запрос
Попытка
Ответ = Соединение.Получить(Запрос);
Если Ответ.КодСостояния = 200 Тогда
// Получаем двоичные данные
ДвоичныеДанныеКартинки = Ответ.ПолучитьТелоКакДвоичныеДанные();
// Проверяем, что это не HTML (проверка по сигнатуре файла или заголовку Content-Type)
ТипКонтента = Ответ.Заголовки.Получить("Content-Type");
Если СтрНайти(ТипКонтента, "text/html") > 0 Тогда
// Сервер все равно вернул HTML (защита сложнее)
Сообщить("Ошибка: Сервер вернул HTML-заглушку вместо картинки.");
Иначе
// Сохраняем файл
ДвоичныеДанныеКартинки.Записать("C:\Temp\image.webp");
Сообщить("Файл успешно скачан.");
КонецЕсли;
Иначе
Сообщить("Ошибка HTTP: " + Ответ.КодСостояния);
КонецЕсли;
Исключение
Сообщить("Ошибка соединения: " + ОписаниеОшибки());
КонецПопытки;
ЗащищенноеСоединениеOpenSSL для работы по HTTPS и явно прописываем User-Agent. Это решает проблему в большинстве случаев, когда защита сайта основана на простых черных списках User-Agent.
Попытка
WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
WinHttp.Option(2) = 1251; // Установка кодировки, если нужно
// Инициализация запроса
WinHttp.Open("GET", "https://example.com/images/photo.webp", 0);
// Установка заголовков
WinHttp.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
WinHttp.SetRequestHeader("Accept", "image/webp,image/apng,image/*,*/*;q=0.8");
// Отправка
WinHttp.Send();
Если WinHttp.Status = 200 Тогда
// Сохранение полученного потока в файл через ADODB.Stream
Stream = Новый COMОбъект("ADODB.Stream");
Stream.Type = 1; // Binary
Stream.Mode = 3; // ReadWrite
Stream.Open();
Stream.Write(WinHttp.ResponseBody);
Stream.SaveToFile("C:\Temp\winhttp_image.webp", 2); // 2 = adSaveCreateOverWrite
Stream.Close();
Сообщить("Скачано через WinHttp");
Иначе
Сообщить("Ошибка сервера: " + WinHttp.Status + " " + WinHttp.StatusText);
КонецЕсли;
Исключение
Сообщить("Ошибка COM-объекта: " + ОписаниеОшибки());
КонецПопытки;
HTTPСоединение, ни WinHttp не помогут.
В этом случае "битый" файл (HTML) содержит скрипт, который браузер должен выполнить. Для решения таких задач в 1С есть два пути:
1. Использование внешних утилит (cURL, Python)
Мы можем вызывать внешние инструменты через ЗапуститьПриложение. Утилита cURL является стандартом для таких задач. Она умеет сохранять Cookies и имитировать браузеры.
2. Получение Cookies вручную
Если защита не меняется динамически, можно один раз зайти на сайт через браузер, скопировать значения куки и добавить их в заголовок запроса в 1С.
magick.exe convert source.webp destination.jpg
HTTPСоединение с подменой заголовка User-Agent на строку из реального браузера.