Как загрузить картинку из интернета в справочник Номенклатура в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

В этой статье мы подробно разберем, как правильно реализовать этот функционал. Мы проанализируем частые ошибки начинающих разработчиков, рассмотрим классический метод загрузки через ХранилищеЗначения, изучим современный и безопасный подход с использованием механизмов Библиотеки стандартных подсистем (БСП), а также научимся выводить загруженные картинки на форму элемента.

Анализ типичных ошибок при загрузке картинок

Давайте сначала разберем, почему у автора исходного сообщения на форуме возникли трудности. Проанализируем ключевые проблемные места в коде:

  1. Запись в реквизиты ссылки вместо объекта. Попытка выполнить код НайденнаяСсылка.Картинка = Новый ХранилищеЗначения(...) приводит к критической ошибке "Поле объекта недоступно для записи". Ссылка в 1С (тип СправочникСсылка) предназначена только для чтения. Чтобы изменить данные элемента, необходимо получить его объект в оперативную память с помощью метода ПолучитьОбъект().
  2. Файлы размером 0 Кб. Это происходит из-за отсутствия проверки ответа веб-сервера. Если сервер возвращает ошибку (например, код 404 "Не найдено", 403 "Доступ запрещен" или 301/302 "Перенаправление"), метод HTTPСоединение.Получить() все равно создаст файл на диске, но он будет пустой или будет содержать служебный HTML-текст ошибки вместо картинки.
  3. Использование жестко зашитых путей. Путь вида "C:\JPG\" несет в себе сразу несколько угроз. Во-первых, у пользователя или службы, под которой запущен сервер 1С, может не быть прав на запись в корень диска C. Во-вторых, если база работает в клиент-серверном режиме, код выполняется на сервере, и папка должна существовать именно на сервере. В-третьих, если сервер 1С работает под управлением Linux, такой путь вызовет фатальную ошибку файловой системы.

Выяснив основные причины ошибок, перейдем к написанию надежного и отказоустойчивого кода.

Решение 1: Классический метод загрузки напрямую в Хранилище Значения

Если вы разрабатываете решение в самописной конфигурации или старой версии базы, где не используется БСП, хранить изображения приходится непосредственно в реквизите справочника Номенклатура с типом ХранилищеЗначения. Рассмотрим правильный алгоритм реализации этой задачи.

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

Посмотрим на пример готовой процедуры:


&НаСервере
Процедура ЗагрузитьКартинкуВХранилище(СсылкаНаТовар, ИсходныйАдресURL)
    
    // Выделяем имя сервера и относительный путь к файлу из общего URL
    // Например, для адреса "https://site.com/images/product123.jpeg"
    Сервер = "site.com";
    ПутьКФайлу = "/images/product123.jpeg";
    
    // Создаем защищенное соединение для работы по протоколу HTTPS
    ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();
    
    // Создаем HTTP-соединение. По умолчанию для HTTPS используется порт 443
    Соединение = Новый HTTPСоединение(Сервер, 443, , , , , ЗащищенноеСоединение);
    
    // Получаем имя для временного файла в системной директории
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("jpeg");
    
    Попытка
        // Отправляем запрос на получение файла
        ОтветСервиса = Соединение.Получить(ПутьКФайлу, ИмяВременногоФайла);
        
        // Проверяем статус-код ответа сервера (200 OK означает успех)
        Если ОтветСервиса.КодСостояния = 200 Тогда
            
            // Получаем объект справочника для редактирования
            ТоварОбъект = СсылкаНаТовар.ПолучитьОбъект();
            
            // Создаем объект Картинка из скачанного файла и помещаем его в ХранилищеЗначения
            НоваяКартинка = Новый Картинка(ИмяВременногоФайла);
            ТоварОбъект.Картинка = Новый ХранилищеЗначения(НоваяКартинка);
            
            // Записываем изменения в базу данных
            ТоварОбъект.Записать();
            
        Иначе
            ВызватьИсключение "Сервер вернул код ошибки: " + ОтветСервиса.КодСостояния;
        КонецЕсли;
        
    Исключение
        // Логируем ошибку в Журнал регистрации для последующего анализа администратором
        ЗаписьЖурналаРегистрации("ЗагрузкаКартинок",
            УровеньЖурналаРегистрации.Ошибка,
            Справочники.Номенклатура,
            СсылкаНаТовар,
            ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
    КонецПопытки;
    
    // Обязательно очищаем за собой временные файлы на диске
    Попытка
        УдалитьФайлы(ИмяВременногоФайла);
    Исключение
        // Ошибку удаления временного файла можно проигнорировать
    КонецПопытки;
    
КонецПроцедуры

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

Решение 2: Современный подход с использованием БСП (Библиотеки стандартных подсистем)

В современных типовых конфигурациях 1С (таких как 1С:Управление торговлей 11, 1С:ERP, 1С:Комплексная автоматизация 2, 1С:Управление нашей фирмой) хранить медиафайлы напрямую в справочнике Номенклатура настоятельно не рекомендуется. Это приводит к быстрому росту размера базы данных и снижению скорости выполнения запросов.

Для хранения картинок используется встроенная подсистема БСП «Работа с файлами». Архитектурно это реализовано следующим образом:

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


&НаСервере
Процедура ЗагрузитьКартинкуНоменклатурыБСП(СсылкаНаНоменклатуру, ИсходныйАдресURL, КодТовара)
    
    Сервер = "site.com";
    ПутьКФайлу = "/images/product123.jpeg";
    
    Соединение = Новый HTTPСоединение(Сервер, 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());
    Запрос = Новый HTTPЗапрос(ПутьКФайлу);
    
    Попытка
        Ответ = Соединение.Получить(Запрос);
        
        Если Ответ.КодСостояния = 200 Тогда
            // Извлекаем двоичные данные картинки прямо из тела HTTP-ответа
            ДвоичныеДанныеКартинки = Ответ.ПолучитьТелоКакДвоичныеДанные();
            
            // Помещаем двоичные данные во временное хранилище платформы
            АдресВременногоХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанныеКартинки);
            
            // Формируем структуру параметров для создания присоединенного файла в БСП
            ПараметрыФайла = Новый Структура;
            ПараметрыФайла.Вставить("Автор", Пользователи.ТекущийПользователь());
            ПараметрыФайла.Вставить("ВладелецФайлов", СсылкаНаНоменклатуру);
            ПараметрыФайла.Вставить("ИмяБезРасширения", "Изображение_" + СокрЛП(КодТовара));
            ПараметрыФайла.Вставить("РасширениеБезТочки", "jpeg");
            
            // Используем стандартный программный интерфейс БСП для добавления файла
            НоваяСсылкаНаФайл = РаботаСФайлами.ДобавитьФайл(ПараметрыФайла, АдресВременногоХранилища);
            
            // Назначаем созданный файл основным изображением для номенклатуры
            ОбъектНоменклатуры = СсылкаНаНоменклатуру.ПолучитьОбъект();
            ОбъектНоменклатуры.ФайлКартинки = НоваяСсылкаНаФайл; 
            ОбъектНоменклатуры.Записать();
            
        КонецЕсли;
    Исключение
        ЗаписьЖурналаРегистрации("ЗагрузкаБСП", УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
    КонецПопытки;
    
КонецПроцедуры

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

Как вывести загруженную картинку на управляемую форму

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

Напрямую связать реквизит типа ХранилищеЗначения с элементом управляемой формы нельзя. Платформа 1С работает по клиент-серверной технологии, поэтому для отображения графических данных на клиенте используется механизм **навигационных ссылок**.

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

  1. Откройте форму элемента справочника Номенклатура в конфигураторе.
  2. В списке реквизитов формы добавьте новый реквизит. Назовите его, например, АдресКартинки. Укажите для него тип данных Строка.
  3. Перетащите созданный реквизит АдресКартинки в левую часть окна — на саму форму.
  4. Выделите добавленный элемент формы и в окне свойств найдите свойство Вид. Измените его значение на Поле картинки.
  5. Теперь нам нужно заполнять этот реквизит формы актуальной навигационной ссылкой при открытии карточки товара. Для этого откройте модуль формы и найдите (или создайте) стандартный обработчик события ПриЧтенииНаСервере.

Напишем код для обработчика чтения данных:


&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    
    // Сценарий 1: Если используется индивидуальный реквизит "Картинка" (тип ХранилищеЗначения)
    Если ЗначениеЗаполнено(Объект.Ссылка) Тогда
        // Формируем навигационную ссылку на реквизит конкретного объекта базы данных
        АдресКартинки = ПолучитьНавигационнуюСсылку(Объект.Ссылка, "Картинка");
    КонецЕсли;
    
    // Сценарий 2: Если используется типовой механизм БСП (через присоединенные файлы)
    // Если ЗначениеЗаполнено(Объект.ФайлКартинки) Тогда
    //     // Формируем ссылку на стандартный реквизит "ФайлХранилище", где БСП хранит бинарные данные
    //     АдресКартинки = ПолучитьНавигационнуюСсылку(Объект.ФайлКартинки, "ФайлХранилище");
    // КонецЕсли;
    
КонецПроцедуры

При открытии карточки товара платформа автоматически прочитает бинарные данные картинки из базы данных по сформированной навигационной ссылке, передаст их на клиентское приложение и отобразит в созданном нами поле формы.

Если в процессе работы пользователь программно меняет изображение, вам достаточно обновить значение реквизита формы АдресКартинки новой навигационной ссылкой и вызвать метод формы ОбновитьОтображениеДанных().

← На главную