В современной практике автоматизации бизнеса часто возникает задача интеграции системы 1С с системами видеонаблюдения. Это может быть фиксация взвешивания автомобилей на складе, распознавание номеров, контроль сборки заказов или фиксация посетителей. Самый простой и быстрый способ получить текущий кадр с IP-камеры — отправить прямой HTTP-запрос к её внутреннему веб-серверу для получения статического JPEG-изображения (снапшота).
В этой статье мы подробно разберем, как правильно настроить такое взаимодействие в 1С, проанализируем типичные ошибки разработчиков, рассмотрим нюансы авторизации различных производителей оборудования и оптимизируем работу с полученными двоичными данными.
Давайте проанализируем ситуацию, с которой часто сталкиваются начинающие разработчики при попытке получить картинку. Код инициализации соединения выглядит следующим образом:
// Ошибочный вариант реализации запроса
Соединение = Новый HTTPСоединение("192.168.0.101",, Имя, Пароль);
Запрос = Новый HTTPЗапрос("http://192.168.0.101/cgi-bin/jpg/image.cgi?");
Ответ = Соединение.Получить(Запрос);
ДвоичныеДанныеКартинки = Ответ.ПолучитьТелоКакДвоичныеДанные();
ДвоичныеДанныеКартинки.Записать("C:\temp\1.jpg");
При выполнении этого кода сервер возвращает ошибку 503 Service Unavailable или 400 Bad Request. Выясним причину этой неполадки.
Дело в том, что при создании объекта HTTPСоединение мы уже жестко указываем адрес хоста (IP-адрес или доменное имя камеры) — в нашем примере это "192.168.0.101". При последующем создании объекта HTTPЗапрос в качестве параметра конструктора необходимо передавать относительный путь к ресурсу на сервере, а не полный абсолютный URL.
Давайте исправим эту ошибку и посмотрим на корректный рабочий пример кода:
// Исправленный и рабочий вариант запроса снапшота
АдресКамеры = "192.168.0.101";
Логин = "admin";
Пароль = "secure_pass_123";
// Инициализируем соединение с указанием хоста и учетных данных
Соединение = Новый HTTPСоединение(АдресКамеры, , Логин, Пароль);
// Указываем только относительный путь к CGI-скрипту получения кадра
ОтносительныйПуть = "/cgi-bin/jpg/image.cgi?";
Запрос = Новый HTTPЗапрос(ОтносительныйПуть);
Попытка
Ответ = Соединение.Получить(Запрос);
Если Ответ.КодСостояния = 200 Тогда
ДвоичныеДанныеКартинки = Ответ.ПолучитьТелоКакДвоичныеДанные();
// Далее обрабатываем полученные двоичные данные
Иначе
ВызватьИсключение "Ошибка камеры. Код состояния: " + Ответ.КодСостояния;
КонецЕсли;
Исключение
ЗаписьЖурналаРегистрации("ПолучениеКадра", УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
Если после исправления адреса на относительный вы всё равно получаете ошибку (например, 401 Unauthorized), дело может быть в используемом типе авторизации.
В платформе 1С передача параметров логина и пароля непосредственно в конструктор HTTPСоединение по умолчанию задействует базовую авторизацию (Basic Authorization). При этом логин и пароль кодируются методом Base64 и передаются в заголовке запроса.
Однако современные IP-камеры ведущих брендов (таких как Hikvision, HiWatch, Dahua) в последних версиях прошивок отключают базовую авторизацию из соображений безопасности, принудительно переводя устройство на авторизацию типа Digest.
У этой проблемы есть два практических решения:
WWW-Authenticate с уникальными параметрами (nonce, realm, qop). На основе этих данных и ваших учетных данных с помощью объекта ХешированиеДанных (алгоритм MD5) вычисляется хэш-ответ, который передается во втором, уже авторизованном запросе.Рассмотрим пример того, как можно вручную сформировать заголовок Basic-авторизации в коде 1С, если стандартный механизм платформы по какой-то причине отрабатывает некорректно:
// Пример ручной сборки заголовка Basic авторизации
СтрокаАвторизации = Логин + ":" + Пароль;
ДвоичныеДанныеСтроки = ПолучитьДвоичныеДанныеИзСтроки(СтрокаАвторизации, КодировкаТекста.UTF8);
КодированныйСтрокой = ПолучитьСтрокуBase64ИзДвоичныхДанных(ДвоичныеДанныеСтроки);
Запрос = Новый HTTPЗапрос("/cgi-bin/jpg/image.cgi?");
Запрос.Заголовки.Вставить("Authorization", "Basic " + КодированныйСтрокой);
Путь /cgi-bin/jpg/image.cgi?, использованный в примере автора темы, индивидуален для его конкретной модели камеры. При переносе вашего программного решения на устройства других вендоров, относительный путь обязательно изменится. Рассмотрим наиболее популярные варианты:
/ISAPI/Streaming/channels/101/picture?snapShotImageType=JPEG (где 101 означает 1-й канал, основной поток; для субпотока используйте 102)./cgi-bin/snapshot.cgiВ кодовой базе старых конфигураций часто встречается запись полученного файла на локальный диск: ДвоичныеДанныеКартинки.Записать("C:\temp\1.jpg");.
В современных реалиях клиент-серверной архитектуры 1С этот подход содержит в себе критические уязвимости:
C:\.Разберем по шагам, как решить эту проблему оптимально и красиво с использованием механизма временных хранилищ 1С v8.3. Этот подход позволяет передавать изображение напрямую в элемент интерфейса формы без сохранения промежуточных файлов на жестком диске.
// Получаем картинку с камеры без сохранения на диск
Ответ = Соединение.Получить(Запрос);
Если Ответ.КодСостояния = 200 Тогда
ДвоичныеДанныеКартинки = Ответ.ПолучитьТелоКакДвоичныеДанные();
// Помещаем двоичные данные во временное хранилище платформы
// УникальныйИдентификатор — это UUID текущей управляемой формы 1С
АдресКартинкиВХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанныеКартинки, УникальныйИдентификатор);
// Теперь мы можем напрямую передать этот адрес реквизиту формы,
// связанному с элементом управления "Поле картинки"
Объект.ПутьККартинкеНаФорме = АдресКартинкиВХранилище;
КонецЕсли;
Если логика бизнес-процесса всё же требует физического сохранения файла на диске (например, для последующей отправки по электронной почте), воспользуйтесь платформенным методом получения уникального пути во временной директории операционной системы:
// Безопасное сохранение во временный файл системы
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("jpg");
ДвоичныеДанныеКартинки.Записать(ИмяВременногоФайла);
// Выполняем действия с файлом...
// После завершения работы обязательно удаляем временный файл
Попытка
УдалитьФайлы(ИмяВременногоФайла);
Исключение
// Обработка исключения, если файл занят другим процессом
КонецПопытки;
Полноценная интеграция систем видеонаблюдения напрямую из кода 1С посредством HTTP-опроса имеет свои архитектурные ограничения. Если камер много (более 10), а запросы кадра происходят часто, процессор IP-камеры может зависнуть от перегрузки веб-сервера.
Для крупных промышленных инсталляций рекомендуется использовать один из альтернативных вариантов: