API 文档

MQHub Web 管理面板 REST API 接口说明,支持用户管理、在线客户端、订阅查询、消息追踪、审计日志、集群节点、消息统计与数据看板

← 返回首页

基本说明

MQHub Web 管理面板提供一组 REST API,用于用户管理、ACL 配置、在线客户端监控、消息追踪、审计日志、消息统计与系统运维。所有接口通过 HTTP 提供服务。

基础地址

http://<服务器IP>:8081

端口可通过环境变量 WEB_PORT 修改(默认 8081)。

请求头

请求头是否必需说明
Authorization是HTTP Basic 认证
Content-Type写操作必需application/json

响应格式

所有接口返回 application/json。成功响应直接返回数据对象,错误响应返回 { "error": "错误说明" }。

单机 / 集群行为差异

当 CLUSTER_MODE 不为 standalone 时,部分接口行为会变化:

接口单机模式集群模式
/health只返回本节点数据额外返回 local_clients
/api/statscluster_nodes 固定为 1cluster_nodes 为实际节点数
/api/cluster/nodes返回虚拟本节点(started_at / last_seen 为 0)返回所有存活节点的完整信息
/api/clients只返回本节点在线客户端合并全集群视图,新增 is_remote 标记
/api/clients/{id}/subscriptions正常返回远程节点客户端返回 501
/api/clients/{id}/kick正常踢下线远程节点客户端返回 501
/api/cache/clear只清本节点缓存广播到全集群,所有节点同步清空

认证方式

所有接口均使用 HTTP Basic 认证,用户名密码与 Web 面板登录凭据一致。

请求头格式

Authorization: Basic <base64(username:password)>

curl 示例

# curl 的 -u 参数会自动生成 Basic Auth 头
curl -u admin:your-password \
  http://127.0.0.1:8081/api/users
⚠️
认证凭据在未启用 HTTPS 时以明文传输。如需保护,请在前置反向代理(如 Nginx)上启用 TLS 并转发到 Web 端口。
💡
所有接口(包括 /health)都需要认证。如监控系统无法携带认证头,请自行通过反向代理放行该路径。

错误响应

错误统一返回 JSON 格式:

{
  "error": "用户已存在"
}

状态码一览

状态码含义典型场景
200成功所有正常响应
400请求参数错误缺字段、格式非法、用户已存在
401未认证缺少或错误的 Authorization 头
403无权限旧密码错误
404资源不存在更新 / 删除不存在的用户,或查询不在线的客户端
501未实现集群模式下操作远程节点的客户端
500服务器内部错误存储后端异常

健康检查

GET /health 返回服务状态与在线客户端数

用于快速判断服务是否存活,并获取当前在线客户端数量。集群模式下会分别返回全集群总数与本地节点数量。

请求示例

curl -u admin:your-password \
  http://127.0.0.1:8081/health

响应示例(单机)

{
  "status": "ok",
  "online_clients": 42,
  "local_clients": 42
}

响应示例(集群,3 节点共 100 在线)

{
  "status": "ok",
  "online_clients": 100,   // 全集群总数
  "local_clients": 35     // 本节点数量
}
字段类型说明
statusstring固定为 ok
online_clientsnumber全集群在线客户端总数(单机模式下等于本节点数量)
local_clientsnumber本节点在线客户端数量

实时数据快照

GET /api/stats 返回当前实时指标快照

返回 Broker 内部实时计数器的快照,用于数据看板展示。只读实时计数器,不存储任何历史数据,对 MQTT 消息路径零影响。

请求示例

curl -u admin:your-password \
  http://127.0.0.1:8081/api/stats

响应示例

{
  // 连接层
  "connections": 10240,
  "uptime_secs": 86400,
  "forwards": 0,

  // 路由层
  "topics": 892,
  "routes": 25300,
  "relations": 25300,

  // 订阅
  "subscriptions": 25300,

  // 用户
  "users": 158,

  // 在线
  "online_local": 10240,
  "online_global": 10240,

  // 节点
  "node_id": 0,
  "node_name": "node-0",
  "cluster_nodes": 1,

  // 部署
  "storage_backend": "sqlite",
  "cluster_mode": "standalone",

  // 时间戳
  "ts": 1735689600000
}

字段说明

字段类型说明
connectionsnumber当前本节点 TCP 连接数(本地 online 表的 size)
uptime_secsnumber进程已运行的秒数(自启动以来的整数)
forwardsnumber集群节点间累计转发消息数。单机模式恒为 0;集群模式下由 RMQTT 底层统计
topicsnumber当前主题数
routesnumber当前路由(订阅关系)数
relationsnumber当前订阅关系数
subscriptionsnumber当前订阅数
usersnumber数据库中的用户总数
online_localnumber本节点在线客户端数
online_globalnumber全集群在线客户端总数(单机模式下等于本节点)
node_idnumber本节点 ID
node_namestring本节点名称
cluster_nodesnumber当前集群节点数(单机固定为 1;集群模式为实际存活节点数,超时节点 30 秒后自动移除)
storage_backendstring存储后端:sqlite / redis
cluster_modestring集群模式:standalone / raft / broadcast
tsnumber响应时间戳(Unix 毫秒)

热门主题 TOP N

GET /api/stats/top-topics 返回订阅数最多的主题列表

从当前订阅关系实时聚合,返回订阅数最多的 TOP 20 主题。按订阅数降序排列。

请求示例

curl -u admin:your-password \
  http://127.0.0.1:8081/api/stats/top-topics

响应示例

{
  "topics": [
    { "topic": "devices/device-001/telemetry", "count": 1520 },
    { "topic": "sensors/+/temp", "count": 890 },
    { "topic": "devices/#", "count": 450 }
  ]
}

字段说明

字段类型说明
topics[].topicstring主题过滤器(Topic Filter)
topics[].countnumber该主题的订阅者数量

协议分布

GET /api/stats/listeners 返回监听器与 MQTT 协议版本分布

返回当前在线客户端按监听器名称(tcp / tls / ws / wss)和 MQTT 协议版本(3.1 / 3.1.1 / 5.0)的分布统计。

请求示例

curl -u admin:your-password \
  http://127.0.0.1:8081/api/stats/listeners

响应示例

{
  "listeners": [
    { "name": "tcp", "count": 8200 },
    { "name": "ws",  "count": 1500 }
  ],
  "protocols": [
    { "name": "MQTT 5.0",   "count": 8000 },
    { "name": "MQTT 3.1.1", "count": 2000 }
  ]
}
💡
该接口需要遍历所有在线 Session 读取协议版本,10 万连接下开销约 ~10ms。建议刷新间隔不低于 3 秒。前端已按 count 降序展示。

集群节点详情

GET /api/cluster/nodes 返回当前存活的所有集群节点

返回当前集群中所有存活节点的信息。单机模式下返回一个虚拟本节点(started_at 和 last_seen 为 0)。

集群模式下,每个节点通过 Redis Pub/Sub 广播心跳(每 10 秒一次),接收端在本地内存表中更新 last_seen。超过 30 秒未收到心跳的节点会被自动从列表中移除。

请求示例

curl -u admin:your-password \
  http://127.0.0.1:8081/api/cluster/nodes

响应示例(单机)

{
  "total": 1,
  "nodes": [
    {
      "node_id": "iZ2ze58hkmkzd2p1bfufjiZ-353909",
      "hostname": "iZ2ze58hkmkzd2p1bfufjiZ",
      "pid": 353909,
      "version": "0.1.1",
      "started_at": 0,
      "last_seen": 0,
      "is_local": true
    }
  ]
}

响应示例(3 节点集群)

{
  "total": 3,
  "nodes": [
    {
      "node_id": "mqhub-01-4128",
      "hostname": "mqhub-01",
      "pid": 4128,
      "version": "0.1.1",
      "started_at": 1735689000000,
      "last_seen": 1735689600000,
      "is_local": true
    },
    {
      "node_id": "mqhub-02-5201",
      "hostname": "mqhub-02",
      "pid": 5201,
      "version": "0.1.1",
      "started_at": 1735689100000,
      "last_seen": 1735689595000,
      "is_local": false
    },
    {
      "node_id": "mqhub-03-6302",
      "hostname": "mqhub-03",
      "pid": 6302,
      "version": "0.1.1",
      "started_at": 1735689200000,
      "last_seen": 1735689598000,
      "is_local": false
    }
  ]
}

字段说明

字段类型说明
totalnumber当前存活节点总数
nodes[].node_idstring节点唯一标识,格式为 hostname-pid
nodes[].hostnamestring节点所在主机名
nodes[].pidnumber进程 PID
nodes[].versionstringMQHub 版本号
nodes[].started_atnumber节点启动时间(Unix 毫秒)。单机模式为 0
nodes[].last_seennumber最近一次收到心跳的时间(Unix 毫秒)。单机模式为 0
nodes[].is_localboolean是否为当前查询的节点(即本节点)
💡
心跳机制:集群模式下,每个节点每 10 秒通过 Redis Pub/Sub 广播一次心跳,接收端在本地内存表更新 last_seen。超时阈值 30 秒,超时节点会被自动过滤,不会出现在响应中。
⚠️
Redis 掉线时的行为:如果集群模式下 Redis 不可达,所有节点都收不到彼此的心跳,30 秒后每个节点的 nodes 列表里只会剩下自己。此时无法区分“其他节点真的掉线”和“Redis 挂了”。建议结合 Redis 监控一起排查。
💡
性能:该接口读取本地内存表,不发起任何 Redis 或网络调用。即使每 3 秒被轮询一次,开销也可忽略不计。

实时统计快照

GET /api/metrics/snapshot 返回完整统计快照(含消息吞吐量)

返回 Broker 内部所有实时统计指标的完整快照,用于管理面板的“实时统计”弹窗。相比 /api/stats,本接口字段更全,并额外包含 消息吞吐量 相关的计数。

按需启用机制

为避免日常运行时产生额外开销,消息吞吐量的统计采用“读取即启用、超时自动关闭”机制:

  • 读取时自动启用:每次调用本接口,会自动打开 PUBLISH 消息计数开关,并续期 30 秒;
  • 无访问自动关闭:30 秒内没有任何调用,后台 watchdog 会自动关闭计数开关;
  • 关闭时零开销:开关关闭时,publish 路径只做一次原子读(~1ns),不产生任何写操作;
  • 启用时精确统计:开关打开时,每条 PUBLISH 消息会增加一次原子计数(~3ns)。

这意味着:不打开统计弹窗,后端几乎没有任何额外开销;打开弹窗才会启动统计。

请求示例

curl -u admin:your-password \
  http://127.0.0.1:8081/api/metrics/snapshot

响应示例

{
  // 消息流量
  "messages_total": 1234567,
  "forwards": 0,
  "retaineds": 156,
  "message_storages": -1,
  "delayed_publishs": 0,

  // 连接会话
  "connections": 10240,
  "connections_max": 10500,
  "sessions": 10100,
  "sessions_max": 10200,
  "handshakings": 88000,
  "handshakings_rate": 3.2,
  "handshakings_active": 5,

  // 订阅路由
  "subscriptions": 25300,
  "subscriptions_shared": 0,
  "topics": 892,
  "routes": 25300,

  // 队列
  "message_queues": 0,
  "out_inflights": 0,
  "in_inflights": 0,

  // 集群
  "cluster_nodes": 1,

  "ts": 1735689600000
}

字段说明

字段类型说明
消息流量
messages_totalnumber累计 PUBLISH 消息数。仅在统计启用期间累加;未启用时返回上一次读取的值
forwardsnumber集群节点间累计转发消息数。单机模式恒为 0
retainedsnumber当前保留消息数。未启用 retainer 插件时为 -1
message_storagesnumber离线消息存储数。未启用 msgstore 插件时为 -1
delayed_publishsnumber延迟发布队列长度。未启用 delayed-publish 插件时为 -1 或 0
连接会话
connectionsnumber当前活跃连接数
connections_maxnumber连接数历史峰值
sessionsnumber当前活跃会话数(持久 + 瞬时)
sessions_maxnumber会话数历史峰值
handshakingsnumber累计完成的 MQTT 握手数
handshakings_ratenumber握手速率(次/秒)
handshakings_activenumber正在进行的握手中数
订阅路由
subscriptionsnumber当前订阅数
subscriptions_sharednumber共享订阅($share)组数
topicsnumber当前主题数
routesnumber当前路由数
队列
message_queuesnumber待发送消息队列长度
out_inflightsnumber出方向 QoS1/2 未确认消息数
in_inflightsnumber入方向 QoS2 未完成消息数
集群
cluster_nodesnumber当前集群节点数(单机固定为 1)
tsnumber响应时间戳(Unix 毫秒)
💡
统计口径:
• messages_total 只统计普通用户的 PUBLISH。超级用户(superuser)绕过 ACL hook,不会被计数;
• 其余字段来自 RMQTT 内置的 scx.stats 快照,每次调用本接口都会刷新;
• handshakings 是累计值,不会随时间下降,除非重启 Broker。
⚠️
性能:每次调用本接口会刷新 scx.stats 快照(约 30 微秒),并在启用期间对每条 PUBLISH 消息增加一次原子计数(约 3ns)。只有在统计弹窗打开时才有这些开销;关闭后 30 秒自动停用。
💡
未启用功能的负数显示:某些字段(如 message_storages)在对应插件未启用时返回 -1,前端会显示为 —,表示“不适用”。这不是错误。

用户列表

GET /api/users 分页查询所有用户

支持分页与搜索,搜索会同时匹配用户名、ACL 中的 clientid 和 topics。

查询参数

参数类型默认值说明
page可选number1页码,从 1 开始
per_page可选number20每页条数,上限由 WEB_PER_PAGE_MAX 控制
search可选string空搜索关键字(不区分大小写)

响应示例

{
  "total": 23,
  "page": 2,
  "per_page": 10,
  "users": [
    {
      "username": "device-001",
      "enabled": true,
      "is_superuser": false,
      "acl_rules": [
        {
          "access": "allow",
          "action": "pubsub",
          "clientid": "device-*",
          "topics": ["devices/device-001/#"]
        }
      ]
    }
  ]
}

创建用户

POST /api/users 新建一个 MQTT 用户

创建成功后,用户立即可用于 MQTT 连接,无需重启服务。集群模式下会通过事件总线广播,所有节点的缓存同步失效。操作会写入审计日志。

请求体

字段类型说明
username*string用户名,唯一,不可为空
password*string密码,不可为空
enabled可选boolean默认 true
is_superuser可选boolean默认 false,超级用户跳过所有 ACL 检查
acl_rules可选arrayACL 规则列表,默认空数组

请求示例

curl -u admin:your-password \
  -X POST http://127.0.0.1:8081/api/users \
  -H 'Content-Type: application/json' \
  -d '{
    "username": "device-001",
    "password": "device-secret",
    "enabled": true,
    "is_superuser": false,
    "acl_rules": [
      {
        "access": "allow",
        "action": "pubsub",
        "clientid": "device-001",
        "topics": ["devices/device-001/#"]
      }
    ]
  }'

成功响应

{
  "status": "created"
}

更新用户

PUT /api/users/{username} 修改指定用户的配置

修改后会自动失效该用户的编译缓存与 ACL 缓存。集群模式下通过 Redis Pub/Sub 广播失效事件,新配置在毫秒级(<100ms)对所有节点生效。

请求示例

curl -u admin:your-password \
  -X PUT http://127.0.0.1:8081/api/users/device-001 \
  -H 'Content-Type: application/json' \
  -d '{
    "username": "device-001",
    "password": "new-secret",
    "enabled": true,
    "is_superuser": false,
    "acl_rules": [
      {
        "access": "allow",
        "action": "pubsub",
        "clientid": "device-001",
        "topics": ["devices/device-001/#"]
      }
    ]
  }'

成功响应

{
  "status": "updated"
}

错误响应

状态码说明
404用户不存在
500写入失败

删除用户

DELETE /api/users/{username} 删除指定用户

删除后该用户立即无法连接(在线连接不会被强制断开,但重新连接会被拒绝)。集群模式下广播到所有节点。

成功响应

{
  "status": "deleted"
}

在线客户端列表

GET /api/clients 分页查询在线 MQTT 客户端

返回当前连接中的客户端信息。集群模式下自动合并本地节点与远程节点的在线客户端,通过 is_remote 字段区分。

查询参数

参数类型默认值说明
page可选number1页码
per_page可选number20每页条数
search可选string空匹配 Client ID / 用户名 / 远程地址

响应示例

{
  "total": 42,            // 过滤后总数
  "grand_total": 100,      // 全集群在线总数
  "local_total": 35,       // 本节点在线数
  "page": 1,
  "per_page": 20,
  "clients": [
    {
      "client_id": "device-001",
      "username": "device-001",
      "remote_addr": "192.168.1.100:54321",
      "local_addr": "0.0.0.0:1883",
      "node_id": 0,
      "listener_id": "tcp",
      "protocol": 5,
      "protocol_name": "MQTT 5.0",
      "keep_alive": 60,
      "clean_start": true,
      "superuser": false,
      "connected": true,
      "session_present": false,
      "connected_at": 1735689600000,
      "created_at": 1735689600000,
      "subscription_count": 3,
      "queue_len": 0,
      "inflight_len": 0,
      "has_will": false,
      "is_remote": false
    }
  ]
}

客户端字段说明

字段类型说明
client_idstringMQTT 客户端 ID
usernamestring登录用户名
remote_addrstring客户端来源地址与端口
local_addrstring服务端本地监听地址(远程节点为空字符串)
node_idnumber集群节点 ID(单机为 0)
listener_idstring监听器名称:tcp / tls / ws
protocolnumber协议版本:3 / 4 / 5(远程客户端为 0)
protocol_namestring协议名称(远程客户端为 "remote")
keep_alivenumberKeepAlive 秒数
clean_startboolean是否 Clean Session
superuserboolean是否为超级用户
connectedboolean连接是否正常
session_presentboolean是否复用了旧的会话
connected_atnumber连接建立时间(Unix 毫秒)
created_atnumber会话创建时间(Unix 毫秒)
subscription_countnumber当前订阅数(远程客户端为 0)
queue_lennumber待发送队列长度
inflight_lennumberQoS 1/2 未确认消息数
has_willboolean是否设置了遗嘱消息
is_remoteboolean是否为远程节点客户端(集群模式)

客户端订阅详情

GET /api/clients/{client_id}/subscriptions 查询指定客户端的订阅主题

支持分页与搜索。集群模式下,若目标客户端在远程节点,会返回 501 Not Implemented。

成功响应

{
  "total": 3,
  "page": 1,
  "per_page": 50,
  "subscriptions": [
    {
      "topic_filter": "devices/device-001/cmd",
      "opts_json": "{\"qos\":1}"
    }
  ]
}

错误响应

状态码说明
404客户端不在线
501客户端在远程节点,需访问该节点

踢客户端下线

POST /api/clients/{client_id}/kick 强制断开指定客户端连接

强制断开指定 MQTT 客户端的连接,常用于:

  • 处理 Client ID 冲突(同一 Client ID 重复登录)
  • 强制异常客户端下线
  • ACL 变更后让旧连接重新认证

操作会写入审计日志,包含操作者用户名和来源 IP。

请求体

字段类型默认值说明
clean_start可选booleantrue是否清除会话状态
clear_subscriptions可选booleanfalse是否清除订阅关系

请求示例

curl -u admin:your-password \
  -X POST http://127.0.0.1:8081/api/clients/device-001/kick \
  -H 'Content-Type: application/json' \
  -d '{"clean_start": true, "clear_subscriptions": false}'

成功响应

{
  "status": "kicked"
}

错误响应

状态码说明
404客户端不在线
501客户端在远程节点,需访问该节点
500踢下线失败(内部错误)
⚠️
集群模式下,远程节点的客户端会返回 501。需要用 node_id 定位客户端实际连接的节点,访问该节点的 Web 面板操作。

启动消息追踪

POST /api/trace/start 开启消息追踪

开启消息追踪,在 MQTT publish 路径上记录事件,用于排障。追踪期间,匹配 topic_filter 的消息会被记录,可通过 /api/trace/events 实时拉取。

请求体

字段类型说明
topic_filter*string要追踪的主题,支持 + 和 # 通配
client_id可选string只追踪指定客户端,留空 = 追踪所有
duration_secs可选number持续时间(秒),10-600,默认 60

请求示例

curl -u admin:your-password \
  -X POST http://127.0.0.1:8081/api/trace/start \
  -H 'Content-Type: application/json' \
  -d '{"topic_filter": "sensors/#", "duration_secs": 60}'

成功响应

{
  "status": "started"
}
⚠️
性能提示:追踪 #(所有主题)且消息频率 > 10000 msg/s 时,会因锁竞争导致吞吐下降 30-50%。建议追踪时缩小 topic 范围,追踪完成后立即停止。

停止消息追踪

POST /api/trace/stop 停止当前追踪

停止当前的消息追踪。停止后,publish 路径恢复 ~1ns 开销(无锁快速路径)。

请求示例

curl -u admin:your-password \
  -X POST http://127.0.0.1:8081/api/trace/stop

成功响应

{
  "status": "stopped"
}

追踪状态

GET /api/trace/status 查询当前追踪状态

返回当前追踪的状态,包括 topic filter、剩余时间、已记录事件数。

响应示例(追踪中)

{
  "active": true,
  "topic_filter": "sensors/#",
  "client_id": null,
  "remaining_secs": 45,
  "event_count": 28
}

响应示例(未追踪)

{
  "active": false
}

拉取追踪事件

GET /api/trace/events 拉取追踪事件(增量)

拉取追踪事件,支持增量拉取(通过 since_ts 参数)。前端建议每 1-2 秒轮询一次。

查询参数

参数类型说明
since_ts可选number只返回时间戳大于此值的事件(Unix 毫秒),用于增量拉取

请求示例

curl -u admin:your-password \
  'http://127.0.0.1:8081/api/trace/events?since_ts=1735689600000'

响应示例

{
  "events": [
    {
      "ts": 1735689600123,
      "client_id": "device-001",
      "username": "device-001",
      "topic": "sensors/temp",
      "payload_size": 25,
      "qos": 1,
      "retain": false,
      "acl_allowed": true
    }
  ]
}

字段说明

字段类型说明
tsnumber事件时间戳(Unix 毫秒)
client_idstring发布消息的客户端 ID
usernamestring发布者的用户名
topicstring消息主题
payload_sizenumberPayload 字节数
qosnumberQoS 等级
retainboolean是否 Retain
acl_allowedbooleanACL 是否通过(true = PASS,false = DENY)

审计日志

GET /api/audit 分页查询操作审计日志

返回所有管理操作的审计记录,包含操作者、时间、操作类型、目标、详情、来源 IP、结果。支持分页和按操作类型过滤。

查询参数

参数类型默认值说明
page可选number1页码
per_page可选number20每页条数,范围 1-200
action可选string空按操作类型过滤,见下表

操作类型(action)

值说明
create_user创建用户
update_user更新用户
delete_user删除用户
kick_client踢客户端下线
trace_start启动消息追踪
trace_stop停止消息追踪
clear_cache清空缓存
change_password修改 Web 密码

请求示例

# 查询第 1 页,每页 20 条
curl -u admin:your-password \
  'http://127.0.0.1:8081/api/audit?page=1&per_page=20'

# 只看踢客户端操作
curl -u admin:your-password \
  'http://127.0.0.1:8081/api/audit?action=kick_client'

响应示例

{
  "total": 156,
  "page": 1,
  "per_page": 20,
  "entries": [
    {
      "ts": 1735689600123,
      "operator": "admin",
      "action": "kick_client",
      "target": "device-001",
      "detail": "{\"clean_start\":true,\"clear_subscriptions\":false}",
      "ip": "192.168.1.100",
      "result": "success"
    },
    {
      "ts": 1735689500000,
      "operator": "admin",
      "action": "create_user",
      "target": "device-002",
      "detail": "{\"enabled\":true,\"is_superuser\":false}",
      "ip": "10.0.0.5",
      "result": "success"
    }
  ]
}

字段说明

字段类型说明
tsnumber操作时间戳(Unix 毫秒)
operatorstring操作者(Web 面板登录用户名)
actionstring操作类型(见上表)
targetstring | null操作目标(用户名 / Client ID),无目标时为 null
detailstring | null操作详情(JSON 字符串),可为空
ipstring | null操作者的来源 IP(非 MQTT 设备 IP),见下方说明
resultstring操作结果:success 或 failed: 原因
💡
关于 IP 字段:
• 记录的是访问 Web 面板的人的 IP(操作者),不是 MQTT 设备的 IP
• 反向代理场景需设 TRUST_PROXY=1 才能拿到真实浏览器 IP(从 X-Forwarded-For 提取)
• 直连场景直接记录 socket 源 IP,不可伪造
• 想看 MQTT 设备的 IP,请查询在线客户端列表的 remote_addr 字段
⚠️
存储上限:Redis 后端保留最近 10000 条(滑动窗口,超出自动淘汰最旧);SQLite 后端无上限。需要长期归档请使用 SQLite 存储后端。

清空缓存

POST /api/cache/clear 清空服务端所有内存缓存

清空用户编译缓存与 ACL 结果缓存。通常在直接修改底层数据库文件后手动调用,通过 API 或 Web 面板改用户时会自动清缓存,无需手动触发。

集群模式下会通过 Redis Pub/Sub 广播到所有节点,所有节点同步清空本地缓存。操作会写入审计日志。

成功响应(单机)

{
  "status": "cache cleared"
}

成功响应(集群)

{
  "status": "cache cleared on all nodes"
}

修改 Web 管理员密码

POST /api/change-password 修改 Web 面板登录密码

修改成功后需要重新登录。新密码会持久化到存储后端,重启服务后依然有效。操作会写入审计日志。

请求体

字段类型说明
old_password*string当前密码
new_password*string新密码,不可为空

请求示例

curl -u admin:old-password \
  -X POST http://127.0.0.1:8081/api/change-password \
  -H 'Content-Type: application/json' \
  -d '{
    "old_password": "old-password",
    "new_password": "new-password"
  }'

错误响应

状态码说明
400新密码为空
403旧密码错误
500数据库写入失败

数据模型

主要数据结构定义。

MqttUser

{
  "username": "string",
  "enabled": true,
  "is_superuser": false,
  "acl_rules": [AclRule, ...]
}

AclRule

{
  "access": "allow",        // allow | deny
  "action": "pubsub",       // publish | subscribe | pubsub
  "clientid": "device-*",   // 支持 * 通配
  "topics": [
    "devices/+/telemetry",     // 支持 + 与 # 通配
    "devices/#"
  ]
}

AuditEntry

{
  "ts": 1735689600000,
  "operator": "admin",
  "action": "kick_client",
  "target": "device-001",
  "detail": "{\"clean_start\":true}",
  "ip": "192.168.1.100",
  "result": "success"
}

分页响应包装

{
  "total": number,        // 过滤后总数
  "page": number,         // 当前页码
  "per_page": number,     // 每页条数
  "users": [...]            // 或 "clients" / "subscriptions" / "entries"
}

错误响应

{
  "error": "错误说明"
}
↑