Homepage 接入 QNAP NAS:QNAP 监控 Widget 配置详解与实现原理
【免费下载链接】homepageA highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations.项目地址: https://gitcode.com/GitHub_Trending/ho/homepage
导读
本文以 QNAP Widget 文档 为主体,讲解如何在 Homepage 首页仪表盘中接入 QNAP NAS,实时展示 CPU 使用率、内存使用率、系统温度和存储池/卷空间占用。文章不仅覆盖完整配置示例与参数说明,还结合仓库中src/widgets/qnap/目录下的代理层、前端组件与测试用例,剖析登录鉴权、会话令牌缓存、多卷聚合等底层实现,帮助你不仅会配,更知道它为什么这样工作。
QNAP Widget 能展示什么
QNAP Widget 属于 Homepage 的服务类 Widget,以widget.type: qnap声明后,会在服务卡片内渲染 4 个指标块,对应文档中声明的允许字段:
| 字段 | 含义 | 前端标签(public/locales/en/common.json#L252-L259) |
|---|---|---|
cpuUsage | CPU 使用率(百分比) | CPU Usage |
memUsage | 内存使用率(百分比) | MEM Usage |
systemTempC | 系统温度(摄氏度) | System Temp |
poolUsage | 存储池使用率(所有卷合计) | Pool Usage |
volumeUsage | 指定单个卷的使用率 | Volume Usage |
注意poolUsage与volumeUsage是二选一的关系:不配置volume字段时显示poolUsage(全部卷聚合),配置了volume字段后则改为volumeUsage(单卷跟踪)。这些标签在 public/locales/en/common.json 中统一定义,并通过 i18n 的common命名空间渲染,因此其他语言包同样包含对应翻译。
最小配置:直接可用
在服务的widget段写入以下内容即可接入 QNAP NAS(原文档示例):
widget: type: qnap url: http://qnap.host.or.ip:port username: user password: pass参数说明:
type:固定为qnap,用于匹配src/widgets/qnap/widget.js导出的 Widget 定义;url:QNAP 设备的管理地址,需包含端口(默认 Web 管理端口 8080,可按实际填写);username/password:QNAP 登录凭据,用于调用 NAS 的 CGI 管理接口(见下文鉴权流程)。
单卷跟踪配置
文档明确指出:如果 QNAP 设备有多个卷,默认的poolUsage会是所有卷的合计值。若只想跟踪某一个卷,在 Widget 配置中追加volume字段即可:
volume: Volume Name From QNAPvolume的值必须是 QNAP 中实际的卷标签(Volume Label),例如DataVol1。该字段的解析在 src/utils/config/service-helpers.js#L562-L564 中与diskstation共用一段逻辑:当类型为["diskstation", "qnap"]时,若存在volume配置项则写入widget.volume,随后由前端组件消费。
工作原理:会话令牌 + 两个数据接口
Widget 前端通过useWidgetAPI(widget, "status")(见 src/widgets/qnap/component.jsx)向代理层请求/status端点,该端点由 src/widgets/qnap/widget.js 中的allowedEndpoints: /status/声明为唯一允许的接口。真正的数据获取全部发生在服务端代理qnapProxyHandler中(src/widgets/qnap/proxy.js),QNAP 密码不会暴露给浏览器。
1. 登录与令牌缓存
QNAP 的 CGI 接口使用基于会话 ID(sid)的鉴权方式。代理层首先向{url}/cgi-bin/authLogin.cgi发送POST请求(proxy.js 的 login 函数):
- 请求头为
Content-Type: application/x-www-form-urlencoded; - 表单携带
user(明文)与pwd(Base64 编码后的密码)两个字段; - 响应是 XML 格式,通过
xml-js的xml2json转换为 JSON 后取出QDocRoot.authSid作为会话令牌。
获取到的令牌以qnapProxyHandler__sessionToken.<service>为键存入memory-cache(sessionTokenCacheKey常量),按服务维度隔离缓存。后续所有数据请求都会携带&sid=<token>参数。令牌无需在每次请求时重复登录,这也是代理层减少对 NAS 负担的关键设计。
2. 两个数据接口
登录成功后,代理层并行发起两个请求(见 proxy.js 的 qnapProxyHandler):
| 数据 | 接口路径 | 用途 |
|---|---|---|
| 系统信息 | {url}/cgi-bin/management/manaRequest.cgi?subfunc=sysinfo&hd=no&multicpu=1 | CPU、内存、温度 |
| 卷用量 | {url}/cgi-bin/management/chartReq.cgi?chart_func=disk_usage&disk_select=all&include=all | 各卷总大小与剩余空间 |
响应同样为 XML,转 JSON 后提取QDocRoot.func.ownContent.root作为system、QDocRoot作为volume返回给前端。
3. 令牌失效自动重登
QNAP 会话令牌会过期。代理层对两种失效场景做了兜底:
- 请求返回HTTP 404;
- 响应中
QDocRoot.authPassed._cdata === "0"(鉴权未通过)。
出现以上情况时,代理层会重新执行login()获取新令牌,并用新令牌重试一次该请求;若重试仍非 200,则记录错误日志并返回data: null。整个重登重试逻辑在 proxy.js 的 apiCall 函数 中实现,前端收到错误后会在容器内展示错误状态(component.jsx中的statusError分支)。
前端指标计算逻辑
src/widgets/qnap/component.jsx 将代理返回的原始 XML-JSON 数据转换为 4 个展示块:
- CPU 使用率:读取
system.cpu_usage._cdata,并剥离尾部的" %"字符串后以百分比渲染; - 内存使用率:由
total_memory与free_memory计算(total - free) / total × 100,结果取整(toFixed(0)); - 系统温度:读取
system.sys_tempc._text,按celsius单位格式化,保留 1 位小数; - 卷/池使用率:优先按
volumeUseList.volumeUse是否为数组区分单卷与多卷场景:- 单卷(非数组):直接使用
total_size与free_size; - 多卷 + 未配置
volume:遍历volumeUse数组,累加所有卷的total_size与free_size(对应文档“poolUsage 是所有卷之和”的说明),再计算使用率; - 多卷 + 已配置
volume:在volumeList.volume中按volumeLabel._cdata精确匹配配置的卷名,命中后取该卷的total_size/free_size计算volumeUsage;若未命中(例如卷名拼写错误),validVolume置为false,该块显示翻译键qnap.invalid(即 “Invalid”),避免渲染出误导性的 0%。
- 单卷(非数组):直接使用
这些计算逻辑均有测试用例覆盖,例如 src/widgets/qnap/component.test.jsx 中构造total_memory = 100、free_memory = 25的载荷,断言内存使用率渲染为75;构造total_size = 100、free_size = 50的单卷数组,断言池使用率为50。加载期间(data未返回)组件渲染 4 个占位 Block,标签同样区分qnap.poolUsage与qnap.volumeUsage。
服务端代理验证
src/widgets/qnap/proxy.test.js 验证了端到端的代理流程:通过 mock 依次返回“登录 → 系统信息 → 卷用量”三段 XML 响应,断言:
- 代理返回 HTTP 200;
res.body.system为系统信息解析结果;res.body.volume包含authPassed字段(即完整QDocRoot对象)。
此外,代理入口会校验req.query中的group与service参数,缺失时返回 400Invalid proxy service type;getServiceWidget找不到对应 Widget 时同样返回 400。这与 Homepage 通用的服务代理模式一致(可参考 docs/widgets/services/index.md 与 docs/configs/services.md 了解服务定义规范)。
使用前提与注意事项
- 需要能访问管理接口:代理层通过 QNAP 的
/cgi-bin/管理 CGI 接口取数,Widget 所在环境(Homepage 容器)必须能通过网络访问该地址,且需在 QNAP 上开启相应管理访问权限; - 凭据安全:密码只在服务端代理层使用,前端与浏览器不会接触到密码;但由于登录接口按文档要求使用 Base64 编码传输,建议仅在可信的内网环境使用;
- 卷名精确匹配:
volume字段必须与 QNAP 卷标签完全一致(区分大小写),否则对应指标块显示Invalid; - 令牌生命周期:会话令牌按 service 维度缓存在内存中并支持失效自动重登,一般无需人工干预;长时间不访问后首次请求可能因重登多一次往返,属正常现象。
小结
QNAP Widget 是 Homepage 服务类 Widget 中典型的“登录鉴权 + 多接口聚合 + 前端计算展示”型组件:widget.js定义接口与白名单,proxy.js负责令牌管理与数据拉取,component.jsx负责指标计算与多卷逻辑,配套测试覆盖了核心路径。按本文配置type: qnap并视需要指定volume字段,即可把 NAS 的关键运行指标直接钉在个人首页上。
【免费下载链接】homepageA highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations.项目地址: https://gitcode.com/GitHub_Trending/ho/homepage
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考