基本说明
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/stats | cluster_nodes 固定为 1 | cluster_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
/health)都需要认证。如监控系统无法携带认证头,请自行通过反向代理放行该路径。错误响应
错误统一返回 JSON 格式:
{
"error": "用户已存在"
}
状态码一览
| 状态码 | 含义 | 典型场景 |
|---|---|---|
| 200 | 成功 | 所有正常响应 |
| 400 | 请求参数错误 | 缺字段、格式非法、用户已存在 |
| 401 | 未认证 | 缺少或错误的 Authorization 头 |
| 403 | 无权限 | 旧密码错误 |
| 404 | 资源不存在 | 更新 / 删除不存在的用户,或查询不在线的客户端 |
| 501 | 未实现 | 集群模式下操作远程节点的客户端 |
| 500 | 服务器内部错误 | 存储后端异常 |
健康检查
用于快速判断服务是否存活,并获取当前在线客户端数量。集群模式下会分别返回全集群总数与本地节点数量。
请求示例
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 // 本节点数量
}
| 字段 | 类型 | 说明 |
|---|---|---|
status | string | 固定为 ok |
online_clients | number | 全集群在线客户端总数(单机模式下等于本节点数量) |
local_clients | number | 本节点在线客户端数量 |
实时数据快照
返回 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
}
字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
connections | number | 当前本节点 TCP 连接数(本地 online 表的 size) |
uptime_secs | number | 进程已运行的秒数(自启动以来的整数) |
forwards | number | 集群节点间累计转发消息数。单机模式恒为 0;集群模式下由 RMQTT 底层统计 |
topics | number | 当前主题数 |
routes | number | 当前路由(订阅关系)数 |
relations | number | 当前订阅关系数 |
subscriptions | number | 当前订阅数 |
users | number | 数据库中的用户总数 |
online_local | number | 本节点在线客户端数 |
online_global | number | 全集群在线客户端总数(单机模式下等于本节点) |
node_id | number | 本节点 ID |
node_name | string | 本节点名称 |
cluster_nodes | number | 当前集群节点数(单机固定为 1;集群模式为实际存活节点数,超时节点 30 秒后自动移除) |
storage_backend | string | 存储后端:sqlite / redis |
cluster_mode | string | 集群模式:standalone / raft / broadcast |
ts | number | 响应时间戳(Unix 毫秒) |
热门主题 TOP N
从当前订阅关系实时聚合,返回订阅数最多的 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[].topic | string | 主题过滤器(Topic Filter) |
topics[].count | number | 该主题的订阅者数量 |
协议分布
返回当前在线客户端按监听器名称(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 }
]
}
count 降序展示。集群节点详情
返回当前集群中所有存活节点的信息。单机模式下返回一个虚拟本节点(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
}
]
}
字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
total | number | 当前存活节点总数 |
nodes[].node_id | string | 节点唯一标识,格式为 hostname-pid |
nodes[].hostname | string | 节点所在主机名 |
nodes[].pid | number | 进程 PID |
nodes[].version | string | MQHub 版本号 |
nodes[].started_at | number | 节点启动时间(Unix 毫秒)。单机模式为 0 |
nodes[].last_seen | number | 最近一次收到心跳的时间(Unix 毫秒)。单机模式为 0 |
nodes[].is_local | boolean | 是否为当前查询的节点(即本节点) |
last_seen。超时阈值 30 秒,超时节点会被自动过滤,不会出现在响应中。
nodes 列表里只会剩下自己。此时无法区分“其他节点真的掉线”和“Redis 挂了”。建议结合 Redis 监控一起排查。
实时统计快照
返回 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_total | number | 累计 PUBLISH 消息数。仅在统计启用期间累加;未启用时返回上一次读取的值 |
forwards | number | 集群节点间累计转发消息数。单机模式恒为 0 |
retaineds | number | 当前保留消息数。未启用 retainer 插件时为 -1 |
message_storages | number | 离线消息存储数。未启用 msgstore 插件时为 -1 |
delayed_publishs | number | 延迟发布队列长度。未启用 delayed-publish 插件时为 -1 或 0 |
| 连接会话 | ||
connections | number | 当前活跃连接数 |
connections_max | number | 连接数历史峰值 |
sessions | number | 当前活跃会话数(持久 + 瞬时) |
sessions_max | number | 会话数历史峰值 |
handshakings | number | 累计完成的 MQTT 握手数 |
handshakings_rate | number | 握手速率(次/秒) |
handshakings_active | number | 正在进行的握手中数 |
| 订阅路由 | ||
subscriptions | number | 当前订阅数 |
subscriptions_shared | number | 共享订阅($share)组数 |
topics | number | 当前主题数 |
routes | number | 当前路由数 |
| 队列 | ||
message_queues | number | 待发送消息队列长度 |
out_inflights | number | 出方向 QoS1/2 未确认消息数 |
in_inflights | number | 入方向 QoS2 未完成消息数 |
| 集群 | ||
cluster_nodes | number | 当前集群节点数(单机固定为 1) |
ts | number | 响应时间戳(Unix 毫秒) |
•
messages_total 只统计普通用户的 PUBLISH。超级用户(superuser)绕过 ACL hook,不会被计数;• 其余字段来自 RMQTT 内置的
scx.stats 快照,每次调用本接口都会刷新;•
handshakings 是累计值,不会随时间下降,除非重启 Broker。
scx.stats 快照(约 30 微秒),并在启用期间对每条 PUBLISH 消息增加一次原子计数(约 3ns)。只有在统计弹窗打开时才有这些开销;关闭后 30 秒自动停用。
message_storages)在对应插件未启用时返回 -1,前端会显示为 —,表示“不适用”。这不是错误。
用户列表
支持分页与搜索,搜索会同时匹配用户名、ACL 中的 clientid 和 topics。
查询参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
page可选 | number | 1 | 页码,从 1 开始 |
per_page可选 | number | 20 | 每页条数,上限由 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/#"]
}
]
}
]
}
创建用户
创建成功后,用户立即可用于 MQTT 连接,无需重启服务。集群模式下会通过事件总线广播,所有节点的缓存同步失效。操作会写入审计日志。
请求体
| 字段 | 类型 | 说明 |
|---|---|---|
username* | string | 用户名,唯一,不可为空 |
password* | string | 密码,不可为空 |
enabled可选 | boolean | 默认 true |
is_superuser可选 | boolean | 默认 false,超级用户跳过所有 ACL 检查 |
acl_rules可选 | array | ACL 规则列表,默认空数组 |
请求示例
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"
}
更新用户
修改后会自动失效该用户的编译缓存与 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 | 写入失败 |
删除用户
删除后该用户立即无法连接(在线连接不会被强制断开,但重新连接会被拒绝)。集群模式下广播到所有节点。
成功响应
{
"status": "deleted"
}
在线客户端列表
返回当前连接中的客户端信息。集群模式下自动合并本地节点与远程节点的在线客户端,通过 is_remote 字段区分。
查询参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
page可选 | number | 1 | 页码 |
per_page可选 | number | 20 | 每页条数 |
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_id | string | MQTT 客户端 ID |
username | string | 登录用户名 |
remote_addr | string | 客户端来源地址与端口 |
local_addr | string | 服务端本地监听地址(远程节点为空字符串) |
node_id | number | 集群节点 ID(单机为 0) |
listener_id | string | 监听器名称:tcp / tls / ws |
protocol | number | 协议版本:3 / 4 / 5(远程客户端为 0) |
protocol_name | string | 协议名称(远程客户端为 "remote") |
keep_alive | number | KeepAlive 秒数 |
clean_start | boolean | 是否 Clean Session |
superuser | boolean | 是否为超级用户 |
connected | boolean | 连接是否正常 |
session_present | boolean | 是否复用了旧的会话 |
connected_at | number | 连接建立时间(Unix 毫秒) |
created_at | number | 会话创建时间(Unix 毫秒) |
subscription_count | number | 当前订阅数(远程客户端为 0) |
queue_len | number | 待发送队列长度 |
inflight_len | number | QoS 1/2 未确认消息数 |
has_will | boolean | 是否设置了遗嘱消息 |
is_remote | boolean | 是否为远程节点客户端(集群模式) |
客户端订阅详情
支持分页与搜索。集群模式下,若目标客户端在远程节点,会返回 501 Not Implemented。
成功响应
{
"total": 3,
"page": 1,
"per_page": 50,
"subscriptions": [
{
"topic_filter": "devices/device-001/cmd",
"opts_json": "{\"qos\":1}"
}
]
}
错误响应
| 状态码 | 说明 |
|---|---|
| 404 | 客户端不在线 |
| 501 | 客户端在远程节点,需访问该节点 |
踢客户端下线
强制断开指定 MQTT 客户端的连接,常用于:
- 处理 Client ID 冲突(同一 Client ID 重复登录)
- 强制异常客户端下线
- ACL 变更后让旧连接重新认证
操作会写入审计日志,包含操作者用户名和来源 IP。
请求体
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
clean_start可选 | boolean | true | 是否清除会话状态 |
clear_subscriptions可选 | boolean | false | 是否清除订阅关系 |
请求示例
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 面板操作。启动消息追踪
开启消息追踪,在 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 范围,追踪完成后立即停止。停止消息追踪
停止当前的消息追踪。停止后,publish 路径恢复 ~1ns 开销(无锁快速路径)。
请求示例
curl -u admin:your-password \
-X POST http://127.0.0.1:8081/api/trace/stop
成功响应
{
"status": "stopped"
}
追踪状态
返回当前追踪的状态,包括 topic filter、剩余时间、已记录事件数。
响应示例(追踪中)
{
"active": true,
"topic_filter": "sensors/#",
"client_id": null,
"remaining_secs": 45,
"event_count": 28
}
响应示例(未追踪)
{
"active": false
}
拉取追踪事件
拉取追踪事件,支持增量拉取(通过 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
}
]
}
字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
ts | number | 事件时间戳(Unix 毫秒) |
client_id | string | 发布消息的客户端 ID |
username | string | 发布者的用户名 |
topic | string | 消息主题 |
payload_size | number | Payload 字节数 |
qos | number | QoS 等级 |
retain | boolean | 是否 Retain |
acl_allowed | boolean | ACL 是否通过(true = PASS,false = DENY) |
审计日志
返回所有管理操作的审计记录,包含操作者、时间、操作类型、目标、详情、来源 IP、结果。支持分页和按操作类型过滤。
查询参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
page可选 | number | 1 | 页码 |
per_page可选 | number | 20 | 每页条数,范围 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"
}
]
}
字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
ts | number | 操作时间戳(Unix 毫秒) |
operator | string | 操作者(Web 面板登录用户名) |
action | string | 操作类型(见上表) |
target | string | null | 操作目标(用户名 / Client ID),无目标时为 null |
detail | string | null | 操作详情(JSON 字符串),可为空 |
ip | string | null | 操作者的来源 IP(非 MQTT 设备 IP),见下方说明 |
result | string | 操作结果:success 或 failed: 原因 |
• 记录的是访问 Web 面板的人的 IP(操作者),不是 MQTT 设备的 IP
• 反向代理场景需设
TRUST_PROXY=1 才能拿到真实浏览器 IP(从 X-Forwarded-For 提取)• 直连场景直接记录 socket 源 IP,不可伪造
• 想看 MQTT 设备的 IP,请查询在线客户端列表的
remote_addr 字段
清空缓存
清空用户编译缓存与 ACL 结果缓存。通常在直接修改底层数据库文件后手动调用,通过 API 或 Web 面板改用户时会自动清缓存,无需手动触发。
集群模式下会通过 Redis Pub/Sub 广播到所有节点,所有节点同步清空本地缓存。操作会写入审计日志。
成功响应(单机)
{
"status": "cache cleared"
}
成功响应(集群)
{
"status": "cache cleared on all nodes"
}
修改 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": "错误说明"
}