Веб сервер

Запускает веб сервер для 'ioBroker драйверов'

Текущий релиз
9.1.16
Разработчик
bluefox
Лицензия
MIT

ioBroker.web

Веб-сервер на базе Node.js и Express для чтения файлов из базы данных ioBroker.

Этот адаптер использует библиотеки Sentry для автоматического сообщения разработчикам об исключениях и ошибках в коде. Более подробную информацию, а также инструкции по отключению отправки сообщений об ошибках см. в документации Sentry-Plugin ! Система отчетности Sentry используется начиная с js-controller 3.0.

Настройка веб-сокетов

У некоторых клиентов, использующих веб-сокеты, возникают проблемы с производительностью связи. Иногда эта проблема связана с переходом на механизм длительного опроса (long polling) при использовании механизма связи socket.io. Вы можете установить параметр «Принудительное использование веб-сокетов» (Force Web-Sockets) , чтобы принудительно использовать только транспорт веб-сокетов.

Сертификаты Let's Encrypt

Читайте здесь

Центр сертификации проверяет HTTP-запрос HTTP-01 на порту 80, поэтому на хосте с одним публичным IP-адресом этот запрос попадает на тот сетевой адаптер, который обслуживает этот порт. При включенных запросах HTTP-01 от Answer ACME (acmeChallenge (по умолчанию) этот экземпляр предоставляет токены. acme адаптер опубликован в /.well-known/acme-challenge/ и acme Адаптеру не нужно останавливать его, чтобы получить доступ к порту. Здесь обрабатывается только запрос на опубликованный токен, все остальное передается без изменений. Отключите эту опцию, чтобы сохранить этот путь исключительно к веб-приложению.

HTTP/2

При включенном HTTPS веб-сервер использует протокол HTTP/2: браузер загружает страницу и все ее файлы по одному соединению с множеством параллельных запросов. Клиенты, не поддерживающие HTTP/2, автоматически переключаются на HTTP/1.1, и веб-сокеты продолжают работать — браузеры открывают их по отдельному соединению HTTP/1.1. Без HTTPS эта опция не работает, поскольку браузеры используют HTTP/2 только поверх TLS.

Если у клиента или веб-расширения возникают проблемы с этим, измените параметр «Использовать HTTP/2» (http2) отключено для сохранения поддержки HTTP/1.1.

Расширения

Веб-драйвер поддерживает расширения. Расширение представляет собой обработчик URL-адресов, который будет вызываться при поступлении запроса по такому URL-адресу. Расширения выглядят как обычный адаптер, но у них нет запущенного процесса, и они будут вызываться веб-сервером.

Например, пользователь может активировать специальный прокси-адаптер и получить доступ к другим устройствам (например, веб-камерам) через тот же веб-сервер. Необходимо, чтобы все сервисы были доступны через один веб-сервер.

Веб-расширение могло бы и должно поддерживать unload функция, которая может возвращать promise если разгрузка займет некоторое время.

Подробнее о веб-расширениях можно прочитать здесь .

Защита методом грубой силы

Если аутентификация включена и пользователь вводит неверный пароль 5 раз в течение одной минуты, он должен подождать не менее одной минуты до следующей попытки. После 15-й неверной попытки пользователь должен подождать 1 час.

Опция "Оставаться в системе"

Если этот параметр выбран, пользователь останется авторизованным в течение одного месяца. В противном случае пользователь останется авторизованным в течение заданного времени ожидания авторизации.

Получите доступ к значениям состояния.

Доступ к значениям нормального состояния можно получить с помощью HTTP-запроса GET.

http://IP:8082/state/system.adapter.web.0.alive =>
{"val":true,"ack":true,"ts":1606831924559,"q":0,"from":"system.adapter.web.0","lc":1606777539894}

или получить доступ к таким файлам, как:

http://IP:8082/vis-2.0/javascript.picture.png =>
[IMAGE]

Начиная с версии 8.0.0, вы также можете записывать значения через HTTP POST-запрос:

[POST] http://IP:8082/state/javascript.0.myVariable => true

Или в виде JSON-объекта с дополнительными параметрами:

[POST] http://IP:8082/state/javascript.0.myVariable =>
{"val": true, "ack": false}

Примечание: для использования этой функции необходимо отключить параметр "Отключить состояния и информацию о сокете" в настройках веб-адаптера.

Доступ к объектам

Вы можете считывать объекты (включая шаблоны с подстановочными знаками) с помощью HTTP GET-запроса. Ответ всегда представляет собой JSON-массив , поскольку шаблон может соответствовать нескольким объектам.

По умолчанию каждый возвращаемый объект содержит только _id, type и common Используйте extended и/или native Флаги запроса для запроса дополнительных данных.

Когда depth Если используется запрос и найден соответствующий объект, расположенный глубже запрошенного уровня, возвращается синтетический заполнитель точно на этой глубине:

{ "_id": "0_userdata.0", "type": "virtual" }

Это позволяет браузеру дерева видеть, что контент существует ниже промежуточного пути, даже если сам этот путь не содержит реального объекта ioBroker. Виртуальные объекты намеренно опускают common чтобы полезная нагрузка была небольшой, отображаемое имя может быть получено из _id Реальный объект с тем же идентификатором всегда имеет приоритет над своим виртуальным заменителем.

http://IP:8082/object/0_userdata.0.branch.* =>
[ { "_id": "0_userdata.0.branch.a", "type": "state", "common": { ... } }, ... ]

Поддерживаемые параметры запроса:

ПараметрОписание
typeФильтрация по типу объекта (например) state, channel, device, folder, enum, instance, ...). **По умолчанию state ** если опущено. Пройти all для запроса объектов любого типа.
commonTypeФильтр по common.type объекта (number, string, boolean, mixed, array, object).
depthМаксимальное количество частей, разделённых точками, в идентификаторе объекта. Например, чтобы получить только непосредственных потомков 0_userdata.0.branch (состоящий из 3 частей), запрос /object/0_userdata.0.branch.*?depth=4. depth=1 молча прикрепляется к depth=2 (Объекты ioBroker существуют на 1 уровне или на 3+ уровнях — записи «экземпляров» 2-го уровня, например) 0_userdata.0 (это то, что на самом деле нужно корневому древовидному браузеру). Любые объекты, состоящие из одного сегмента, удаляются из ответа по той же причине.
extendedПроходить ?extended или ?extended=true дополнительно включить такие атрибуты системы, как acl, from, ts, user, enums, _rev.
nativeПроходить ?native или ?native=true дополнительно включить native часть каждого объекта.
systemПо умолчанию объекты находятся в system.* и script.* скрыты . Пропуск ?system или ?system=true включить их.

Примеры:

[GET] http://IP:8082/object/0_userdata.0.branch.*?depth=4&type=all
[GET] http://IP:8082/object/0_userdata.0.*?type=state
[GET] http://IP:8082/object/0_userdata.0.*?type=state&commonType=boolean
[GET] http://IP:8082/object/system.adapter.web.0?native=true
[GET] http://IP:8082/object/system.adapter.web.0?extended=true&native=true
[GET] http://IP:8082/object/system.adapter.web.0

Примечание: для использования этой функции необходимо отключить параметр "Отключить доставку объектов" в настройках веб-адаптера.

Ранее существовал встроенный "простой API".

Вплоть до версии 6.x этот адаптер имел встроенный переключатель «Simple-API» , который отвечал на такие адреса, как... http://ip:8082/get/<id> и http://ip:8082/set/<id>?value=… напрямую. Переключатель исчез начиная с версии 7.0. simple-api Адаптер перенял эту функцию и может быть запущен внутри этого веб-сервера как веб-расширение, которое возвращает старые адреса без изменений — никаких скриптов, использующих их, трогать не нужно.

Настройка

  1. Установите адаптер** simple-api ** и создать его экземпляр.
  2. Откройте настройки этого экземпляра и установите для параметра "Веб-экземпляр" значение, соответствующее веб-экземпляру, который должен его обслуживать, например. web.0 (Оставлено пустым, simple-api Вместо этого он запускает собственный сервер на порту 8087 — это тоже работает, но тогда в адресах будет указан его порт, а не порт этого сервера.
  3. Сохраните. Веб-экземпляр перезапускается и сообщает о смонтированных путях в своем журнале.

Адреса

Работает как расширение, simple-api ответы под двумя префиксами:

http://ip:8082/get/<id>                     the address as it was up to web 6.x
http://ip:8082/simple-api.0/get/<id>        the same, below the name of the instance

Таким образом, для существующих скриптов ничего не меняется:

http://ip:8082/set/0_userdata.0.Alarm.disable?value=true
http://ip:8082/getPlainValue/0_userdata.0.Temperature

Команды — это хорошо известные команды: get, getPlainValue, getBulk, set, setBulk, setValueFromBody, toggle, getObjects, objects, getStates, states, search и query.

Аутентификация

От имени какого пользователя будет выполняться запрос, определяется настройками аутентификации данного веб-экземпляра:

  • Выкл . — Каждый запрос выполняется от имени пользователя, указанного в разделе «Доступ к веб-интерфейсу от имени».
  • Запрос должен идентифицировать себя одним из трех способов: с сессией браузера, подключенного к этому серверу, или с помощью Authorization: Basic заголовок или с ?user=…&pass=… в строке запроса. Учетные данные в строке запроса передаются в открытом текстовом виде и попадают в журналы и историю браузера, поэтому используйте последний вариант только по протоколу HTTPS, если вообще используете его.

Если вы предпочитаете использовать более новый API

rest-api Это преемник с версионированным интерфейсом, работающий как веб-расширение аналогичным образом. Его адреса отличаются. get/<id> становится v1/state/<id> и полный объект состояния требует ?withInfo=true:

http://ip:8082/v1/state/<id>?withInfo=true

Опция "Базовая аутентификация"

Позволяет выполнить вход через базовую аутентификацию путем отправки 401 Несанкционированное использование WWW-Authenticate Заголовок. Его можно использовать для таких приложений, как FullyBrowser . При вводе неверных учетных данных вы будете перенаправлены на страницу входа.

Список пользователей

Вы можете определить список пользователей, имеющих доступ к веб-серверу. Вы можете изменить права доступа для авторизованных пользователей.

Если пользователя нет в списке, он не сможет получить доступ к веб-серверу.

Проще установить для каждого объекта и каждого состояния права доступа для конкретного пользователя.

Помимо отдельных пользователей, вы можете разрешить вход целым группам. Пользователь может войти в систему, если он находится в списке пользователей или является членом одной из разрешенных групп — неважно, в какой именно группе он состоит. Члены разрешенной группы отображаются в списке пользователей как уже выбранные, поэтому добавлять их повторно не нужно. Добавление группы позволяет сократить список: любой, кто присоединится к группе позже, сможет войти в систему без изменения текущего экземпляра.

С помощью веб-интерфейса доступа вы сами определяете, с какими правами будет осуществляться доступ:

  • Для авторизованного пользователя у каждого сохраняются свои права доступа, поэтому каждый пользователь видит только то, что разрешено его группами.
  • Для конкретного пользователя — каждый разрешенный вход в систему осуществляется с правами этого пользователя, независимо от того, кто вошел в систему. Это простой способ позволить нескольким людям совместно использовать один набор разрешений.

Вход в систему, не соответствующий ни пользователям, ни группам, отклоняется, и это регистрируется в журналах экземпляра. User system.user.<name> is not in the user list.

Этот список определяет только , кто может войти в систему — он не предоставляет никаких прав. За ним по-прежнему действуют обычные списки контроля доступа ioBroker, поэтому пользователю необходимы права на чтение объектов, состояний и файлов, которые он должен видеть. Таким образом, группа со всеми включенными разрешениями не то же самое, что группа администраторов: члены system.group.administrator Пройти проверку каждого файла, все остальные должны пройти проверку ACL для отдельного файла. Файлы, загруженные с помощью 0x660 (defaultNewAcl.file в system.config) не предоставляют никаких прав "другим", поэтому адаптер, файлы которого выглядят таким образом, отвечает ошибкой 404 пользователю, который не является ни его владельцем, ни членом группы владельцев.

Расширенные параметры

Перенаправление по умолчанию

Если при открытии веб-порта в браузере не должно отображаться меню выбора приложения, а должно отображаться какое-либо конкретное приложение, путь к нему можно указать здесь (например, /vis/ Таким образом, этот путь откроется автоматически.

Встраивание этого сервера в другой сайт

Браузер обрабатывает cookie-файл без SameSite атрибут как SameSite=Lax и сохраняет его за собой, как только страница переходит на другой источник. Панель управления, которая встраивает страницу этого сервера в <iframe> Таким образом, запрос отправляется без сохранения сессии, и пользователю предлагается снова войти в систему внутри фрейма — в то время как открытая напрямую та же страница работает корректно.

Функция "Разрешить встраивание на другие сайты" отправляет сессионный cookie с SameSite=None; Secure и позволяет реализовать это дело. В комплекте идут две вещи:

  • Для этого требуется TLS. Браузеры его принимают. SameSite=None только вместе с Secure и cookie-файл, помеченный как безопасный, никогда не передается по обычной сети. http:// Таким образом, либо включите шифрование здесь, либо завершите TLS на обратном прокси-сервере перед этим сервером и установите публичный URL-адрес на его https:// Адрес — этот параметр игнорируется, и в журнале появляется предупреждение, хотя ни то, ни другое не соответствует действительности. В варианте с прокси-сервером прокси-сервер должен отправлять X-Forwarded-Proto: https Именно так этот сервер узнает, что браузер использовал с ним протокол TLS. Без этого заголовка сессионный cookie вообще не выдается, и никто не может войти в систему.
  • Оно отказывается от того, что SameSite Защита от: сессионный cookie отправляется с запросами, поступающими с любого другого сайта, а не только с того, в который вы встроили этот сервер. Не включайте его, если вы фактически не встраиваете этот сервер куда-либо еще.

Это также зависит от того, принимает ли браузер сторонние cookie-файлы, от которых семейство Chromium постепенно отказывается. Единственный способ, который продолжает работать, — это использование токена OAuth2 в URL-адресе вместо cookie-файла, что вообще не требует межсайтовых cookie-файлов:

<iframe src="https://iobroker.example.com:8082/some-page?token=<access_token>"></iframe>

Аутентификация OAuth2

Веб-адаптер поддерживает аутентификацию OAuth2.

Для получения токенов пользователю необходимо перейти по следующему URL-адресу:

http://ip:8082//oauth/token?grant_type=password&username=<user>&password=<password>&client_id=ioBroker&stayloggedin=<false/true>

stayloggedin=true Это означает, что токен будет сохранен в браузере и будет использоваться для последующих запросов; его использование необязательно.

Ответ выглядит так:

{
    "access_token": "21f89e3eee32d3af08a71c1cc44ec72e0e3014a9",
    "expires_in": "2025-02-23T11:39:32.208Z",
    "refresh_token": "66d35faa5d53ca8242cfe57367210e76b7ffded7",
    "refresh_token_expires_in": "2025-03-25T10:39:32.208Z",
    "token_type": "Bearer"
}

Более подробную информацию можно найти здесь: https://github.com/ioBroker/webserver?tab=readme-ov-file#oauth2-support

Авторизация сторонних клиентов (OAuth)

Указанная выше конечная точка для ввода токена требует, чтобы клиент обрабатывал пароль пользователя ioBroker. Клиенты, работающие вне вашего контроля — клиенты MCP или веб-расширения, обслуживающие их, — не должны этого делать. Включение параметра «Разрешить сторонние клиенты» в настройках дополнительно обеспечивает поток авторизации OAuth2 на основе кода в браузере с использованием PKCE: клиент перенаправляется на страницу входа и согласия, пользователь подтверждает авторизацию, и клиент получает токен, привязанный к запрошенному ресурсу.

По умолчанию эта функция отключена. При включении:

  • Клиенты обнаруживают сервер через /.well-known/oauth-authorization-server и зарегистрироваться самостоятельно, если параметр "Разрешить саморегистрацию клиентов" не отключен.
  • Неаутентифицированные запросы, которые не запрашивают text/html на них отвечают следующим образом 401 и а WWW-Authenticate Вместо перенаправления на страницу входа в систему используется запрос подтверждения — перенаправление бесполезно для клиента API. Браузеры не затрагиваются.
  • Веб-расширения публикуют собственные метаданные ресурсов в разделе /.well-known/oauth-protected-resource/<path> Эти документы остаются читаемыми и без ввода учетных данных.
  • Укажите публичный URL-адрес, если сервер работает за обратным прокси-сервером, и используйте HTTPS: удаленные клиенты отказываются от использования обычного протокола. http://.

9.1.12 (2026-10-04)

  • (@GermanBluefox) Исправлено: при включенном кэшировании файл, который адаптер записывает повторно под тем же именем, доставляется заново, а не навсегда в той версии, которая была прочитана первой. Именно это и привело к ошибке. sayit Повторить то же самое объявление. Кэш вообще не мог узнать об изменении — адаптер никогда не подписывался на файлы, которые он кэшировал. Теперь он это делает, только для этих пространств имен, и удаляет запись при изменении файла.
  • (@GermanBluefox) Исправлено: адаптер, работающий как веб-расширение, на странице обзора связан с этим сервером, а не с собственным портом, который ничего не прослушивает. Запись, предоставляемая таким адаптером, через welcomePage() был собран после того, как список уже был очищен, а его ссылки исправлены, поэтому он так и не получил... localLink Страница была прочитана, но затем удалена без объяснений, осталась только неработающая ссылка. common.localLinks позади
  • (@GermanBluefox) Индекс папок получил внешний вид административной панели: панель приложений с путем и количеством записей, значки, отличающие папку от файла, размеры в удобочитаемых единицах измерения, а также светлая и темная темы, которые страница выбирает сама из настроек системы. Папка размером 0 байт отображается как «0 Б» вместо ничего, и путь вверх больше не предлагается в корне адаптера, где он выходил из него.
  • (@GermanBluefox) Непредвиденная ошибка при чтении сессии больше не завершает работу экземпляра. Хранилище сессий отвечает из собственной задачи, поэтому исключение в одном из его коллбэков не достигло ни Express, ни A. try/catch И контроллер завершил работу всего веб-сервера из-за одного запроса. Четыре функции обратного вызова теперь защищены и отвечают кодом 500. То же самое произошло и с двумя промисами. onObjectChange /onStateChange без catch где отклоненное чтение URL-адреса сокета было расценено как необработанное отклонение.
  • (@GermanBluefox) Добавлена опция "Разрешить встраивание на другие сайты": сессионный cookie отправляется вместе с SameSite=None; Secure Таким образом, страница этого сервера сохраняет свою сессию, даже когда другой сайт встраивает её в iframe. Здесь требуется SSL или обратный прокси-сервер HTTPS с заданным публичным URL-адресом, и по умолчанию он отключен, поскольку это снижает уровень защиты. SameSite защищает от запросов иностранных страниц
  • (@GermanBluefox) Исправлено: вызов /prolongSession Больше не завершает работу экземпляра. Сессия была передана хранилищу без указания времени жизни, хранилище само получило объект сессии, а проверка типа контроллера завершила работу адаптера с сообщением "Параметр ttl должен быть числового типа". Сессия также записывается обратно под идентификатором, который содержит её cookie. req.session.id Ситуация меняется, как только express-session запускает новую сессию для запроса, и затем продолжается неправильная сессия.
  • (@GermanBluefox) Исправлено: адрес без закрывающей косой черты -/vis-2 вместо /vis-2/ — приводит к переходу на сайт приложения вместо ошибки 404. В ответ происходит перенаправление на адрес с косой чертой, как и на любом другом веб-сервере.
  • (@GermanBluefox) Ошибка 404 указывает на запрошенный адрес, а не на имя файла, оставшееся после удаления имени адаптера, и регистрирует это на уровне отладки.
  • (@hdering) Веб-экземпляр, перезапускающийся для загрузки измененного веб-расширения, регистрирует это как info с указанием причины вместо предупреждения "Завершено (-100): Без причины"

9.1.11 (2026-10-02)

  • (@hdering) Обновление адаптера с помощью веб-расширения перезапускает только те экземпляры веб-сервера, которые его используют, а не все экземпляры веб-сервера.
  • (@GermanBluefox) Исправлено: пользователь, которого список пользователей разрешает через группу, разрешается независимо от того, к какой из этих групп он принадлежит. Сравнивалась только первая группа, в которой состоял пользователь, с разрешенными, поэтому пользователь, состоящий в нескольких группах, получал отказ, если первая группа не была указана в списке. Порядок групп соответствует порядку их создания, что создавало впечатление произвольности.

9.1.9 (2026-09-28)

  • (@GermanBluefox) Добавлено состояние onScreen для приложения

9.1.8 (2026-09-24)

  • (@GermanBluefox) Пустое тело для cloud.X.remote.command Вместо записи пустой команды, которая отбрасывается без каких-либо слов, отправляется ошибка 400.

9.1.7 (2026-09-21)

  • (@joltcoke) Исправлено: после авторизации пользователь снова попадает на запрошенную страницу, даже если в её URL содержится строка запроса. Целевой адрес проверялся после декодирования по списку символов без "=", поэтому каждый реальный параметр запроса отправлял пользователя на корневую страницу. Фрагмент запрошенного URL также сохраняется.
  • (@GermanBluefox) Исправлено: при неправильном вводе пароля происходит возврат на страницу входа с сообщением об ошибке вместо ошибки 404, и запрошенная страница не теряется при переходе на другую страницу.
  • (@GermanBluefox) Исправлено: прямая ссылка, на которую был дан ответ в виде файла JavaScript, сохраняет всю строку запроса — она обрезалась на первом символе "&".
  • (@GermanBluefox) Целевой объект, содержащий управляющий символ, снова отклоняется: браузеры удаляют символы табуляции и перевода строки перед тем, как прочитать URL-адрес, который превратился в "/" /host" в ссылку, которая ведет за пределы этого сервера

License

The MIT License (MIT)

Copyright (c) 2014-2026 Bluefox dogafox@gmail.com

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.