linux-dash 2.0 API 接口详解

逐个实测 linux-dash 2.0 的 29 个监控模块端点与 WebSocket 通道:请求格式、响应 JSON 字段解读、轮询间隔与前端刷新关系,以及依赖缺失、脚本损坏时的真实报错与修复排障。

linux-dashLinux系统监控可观测性2026/10/24

linux-dash 2.0 API 接口详解

目标:把 linux-dash 2.0 服务端暴露的全部数据接口——GET /server/?module=<模块名> 的 29 个监控模块与 WebSocket 通道——逐个讲清:请求格式、实测响应回显、JSON 字段含义、前端各页签的轮询刷新关系,以及依赖缺失、脚本损坏时的真实报错与修复方法。全部命令与回显已在 Ubuntu 22.04 环境实测通过(Node.js 主路径实测为主,PHP/Apache 路径差异单独标注)。安装部署见 《Ubuntu 22.04 安装 linux-dash 指南》,运行参数与模块级开关见 《linux-dash 配置参数详解》。

一、环境信息

本文在三类 Ubuntu 22.04 服务器环境中完成实测,分别代表「依赖完整」「PHP 最小安装」「裸系统最小化」三种真实运维场景。linux-dash 的 API 是一组对系统命令的封装,模块能不能出数,完全取决于所在服务器装没装对应的命令行工具——这也是本文把三类环境都纳入实测的原因。

环境角色操作系统linux-dash 运行方式关键依赖状态
服务器甲依赖完整主环境Ubuntu 22.04.5 LTS(内核 6.8.0-138-generic,12 核 / 32 GB 内存)Node.js v20.20.2 直跑 app/server/index.js,nginx 1.18.0 反代 8080 + HTTP Basic 认证net-tools、gawk、lsb-release、pm2 已装;dig、sensors、redis-cli、nc、docker 未装
服务器乙PHP 备查环境Ubuntu 22.04Apache 2.4.52 + PHP 8.1.2,入口 /server/index.php仅 net-tools、lsb-release;awk 为系统默认 mawk
服务器丙最小化对照环境Ubuntu 22.04(systemd 托管服务)Node.js 直跑 app/server/index.js,systemctl 管理的 linux-dash 服务初始仅 node、curl 可用;netstat/arp/ifconfig 在第七章问题 1 的排障复测中补装;dig/sensors/gawk/lsb-release(后续补装验证)/redis-cli/nc/docker/pm2 缺失

服务器甲的依赖盘点命令与实测回显(缺失项输出 MISSING):

# 在面板所在服务器上逐项盘点 API 依赖的命令是否可用
command -v netstat || echo MISSING
command -v arp || echo MISSING
command -v ifconfig || echo MISSING
command -v dig || echo MISSING
command -v sensors || echo MISSING
command -v gawk || echo MISSING
command -v lsb_release || echo MISSING
command -v redis-cli || echo MISSING
command -v nc || echo MISSING
command -v docker || echo MISSING
command -v pm2 || echo MISSING

实测回显(服务器甲):

/usr/bin/netstat
/usr/sbin/arp
/usr/sbin/ifconfig
MISSING
MISSING
/usr/bin/gawk
/usr/bin/lsb_release
MISSING
MISSING
MISSING
/usr/bin/pm2

其他版本信息(服务器甲实测):

node --version
curl --version | head -1
nginx -v
v20.20.2
curl 7.81.0 (x86_64-pc-linux-gnu) libcurl/7.81.0 OpenSSL/3.0.2 zlib/1.2.11 brotli/1.0.9 zstd/1.4.8 libidn2/2.3.2 libpsl/0.21.0 (+libidn2/2.3.2) libssh/0.9.6/openssl/zlib nghttp2/1.43.0 librtmp/2.3 OpenLDAP/2.5.20
nginx version: nginx/1.18.0 (Ubuntu)

💡 说明:curl 回显中 libssh/nghttp2/OpenLDAP 等子库版本随发行版补丁浮动,以 curl --version 实际输出为准,不影响 API 行为。

二、前置条件

本章确认调用 API 前必须满足的三个前提:入口可达、认证方式、客户端工具。

2.1 API 入口与网络可达性

linux-dash 2.0 的服务端入口因安装路径而异(两种路径的安装过程见 《Ubuntu 22.04 安装 linux-dash 指南》):

安装路径API 入口说明
Node.js 路径(官方推荐)http://<服务器IP>:<端口>/server/?module=<模块名>Express 直出,监听地址/端口由启动参数或环境变量决定,默认 0.0.0.0:80
PHP + Apache 路径http://<服务器IP>/server/index.php?module=<模块名>index.php 以 shell_exec 调同一个 linux_json_api.sh;在 DirectoryIndex 含 index.php 时 /server/?module= 等价

验证入口可达的最直接方式(服务器甲实测):

curl -s http://127.0.0.1/server/?module=general_info
{ "OS": "Ubuntu 22.04.5 LTS 6.8.0-138-generic", "Hostname": "linuxdash-node", "Uptime": " 4 days 2 hours 17 minutes and 23 seconds ", "Server Time": "Fri Oct 23 18:05:20 UTC 2026" }

能取到这段 JSON 即入口可达、服务端工作正常。

2.2 认证前提

linux-dash 2.0 服务端自身不提供任何认证机制——API 与首页完全裸奔,鉴权只能靠反向代理层叠加。本文实测环境在 nginx 反代(监听 8080)上启用了 HTTP Basic 认证,认证配置细节见 《linux-dash 配置参数详解》;本文第四章给出带认证的完整调用实测。

💡 技术拓展:给「无认证 API」加鉴权,反代层的常见选项对比——

方案原理/特点适用场景
HTTP Basic 认证用户名口令 Base64 编码传输,配置最简单内网/HTTPS 通道下的管理面板
mTLS 客户端证书双向证书校验,无口令泄露面安全等级要求高的运维专网
IP 白名单allow/deny 按源地址放行访问来源固定的运维跳板
OAuth2/JWT 网关引入认证服务与令牌校验多面板统一身份的企业环境

linux-dash 定位是单人/小团队自托管监控,官方文档采用 HTTP Basic 认证,本文实测亦采用该方案(admin + 反代侧配置)。

2.3 客户端工具

调用 API 只需要 curl(7.x 即可,Ubuntu 22.04 自带)。调试 WebSocket 通道时需要一个能发 WebSocket 帧的客户端,本文直接用 linux-dash 自带的 Node.js websocket 库写探针脚本(见 5.8 节)。

三、API 总览

linux-dash 2.0 的 API 面非常小而固定:一个 REST 数据端点、一个 WebSocket 通道探测端点、一个 WebSocket 数据通道。无版本化路径、无分页、无过滤参数、无排序参数、无限流中间件——请求粒度就是「一个模块一次调用」。

3.1 端点清单

端点方法作用
/server/?module=<模块名>GET执行对应监控模块,返回原始 JSON/文本数据
/websocketGET探测服务端是否支持 WebSocket,返回 {"websocket_support":true}
/websocket(Upgrade 后)WebSocket发送模块名文本,服务端推送该模块数据(存在 JSON 拼接缺陷,见 5.8 节)
/GET返回面板首页 HTML(ng-app="linuxDash")

服务器甲实测 /websocket 探测端点:

curl -s http://127.0.0.1/websocket
{"websocket_support":true}

3.2 请求与响应约定

实测归纳的约定如下:

  • 请求:仅支持 GET。对 /server/ 发 POST 实测返回 404(Express 默认 404 页,Content-Type: text/html):
curl -s -i -X POST 'http://127.0.0.1/server/?module=load_avg' | head -10
HTTP/1.1 404 Not Found
X-Powered-By: Express
Content-Security-Policy: default-src 'none'
X-Content-Type-Options: nosniff
Content-Type: text/html; charset=utf-8
Content-Length: 147
Date: Fri, 23 Oct 2026 18:23:08 GMT
Connection: keep-alive
Keep-Alive: timeout=5
  • 响应头:Content-Type 固定为 text/html; charset=utf-8 而不是 application/json(实测见 4.1 节),带 X-Powered-By: Express 与 ETag。程序化消费时不能依赖 Content-Type 判别,需自行按 JSON 解析。
  • 成功语义:模块脚本退出码为 0 时返回 200 + 脚本标准输出原文;退出码非 0 时返回 500(实测见第七章问题 4)。
  • 未知模块语义:模块名不匹配任何已定义函数时,仍返回 200,响应体是字面量 {\"success\":false,\"status\":\"Invalid module\"}(含反斜杠转义引号、并非合法 JSON,实测见第七章问题 7)。
  • 分页/过滤/排序:均不支持。数据量由模块自身决定(如进程类模块固定返回前 15 条)。

3.3 监控模块清单(29 个)

app/server/linux_json_api.sh 内定义 29 个模块函数,模块名即 module 参数取值。下表为全量清单、数据来源与前端页签归属:

模块名数据来源前端页签前端插件类型
general_infolsb_release / uname / hostname / /proc/uptime / dateBasic Infokey-value(一次性)
number_of_cpu_cores/proc/cpuinfo无(内部辅助函数,正常时无输出)—
cpu_infolscpuBasic Infokey-value(一次性)
cpu_utilization/proc/stat 两次采样System Status折线图(轮询)
load_avg/proc/loadavgSystem Status多折线图(轮询)
cpu_templm-sensors(树莓派专用路径除外)System Status折线图(轮询)
cpu_intensive_processesps 按 CPU 排序System Status表格(一次性)
ram_intensive_processesps 按内存排序System Status表格(一次性)
current_ram/proc/meminfoSystem Status折线图(轮询)
memory_info/proc/meminfo 全文Basic Infokey-value(一次性)
swap/proc/swapsSystem Status表格(一次性)
disk_partitionsdf -PhSystem Status表格(一次性)
io_stats/proc/diskstatsBasic Info表格(一次性)
bandwidth/proc/net/dev 累计字节数Network表格(一次性)
download_transfer_rate/sys/class/net/*/statistics/rx_bytes 两次采样Network多折线图(轮询)
upload_transfer_rate/sys/class/net/*/statistics/tx_bytes 两次采样Network多折线图(轮询)
ip_addressesifconfig + dig(外部 IP)Network表格(一次性)
network_connectionsnetstat -ntu 聚合Network表格(一次性)
arp_cachearpNetwork表格(一次性)
pingping(目标清单在 config/ping_hosts)Network表格(一次性)
docker_processesdocker ps + docker topSystem Status表格(一次性)
logged_in_usersw -hAccounts表格(一次性)
recent_account_loginslastlog -t 365Accounts表格(一次性)
user_accounts/etc/passwdAccounts表格(一次性)
common_applicationswhereis 13 个常用程序Apps表格(一次性)
memcachednc 127.0.0.1 11211 statsAppskey-value(一次性)
redisredis-cli INFO(取 6 项)Appskey-value(一次性)
pm2_statspm2 list(按固定列位解析)Apps表格(一次性)
scheduled_crons/etc/crontab + /etc/cron.d/* + 用户 crontabBasic Info表格(一次性)
cron_history/var/log/syslog 中 CRON 日志Basic Info表格(一次性)

💡 技术拓展:监控面板取数通道不止 linux-dash 用的「REST 轮询 + WebSocket 推送」,常见方案对比——

通道原理/特点代表产品
REST 轮询前端定时 GET,实现最简单、延迟=轮询间隔linux-dash(REST 兜底)
WebSocket 全双工建连后双向推送,省重复握手linux-dash(优先通道)
SSE 单向推送服务端单向流,HTTP 原生、自动重连各类日志/行情面板
长轮询服务端挂住请求至有数据再返回早期 Web IM/监控

linux-dash 2.0 实际采用「WebSocket 优先、REST 兜底」双通道(分流逻辑见 server.service.js,6.1 节),且 WebSocket 通道存在输出转义缺陷,工程上建议以 REST 通道为准。

3.4 服务端执行链

Node.js 路径下,每次 /server/?module=X 请求的执行链(app/server/index.js 源码逻辑,实测核对):

  1. Express 路由 app.get('/server/') 读取 req.query.module;
  2. spawn 拉起子进程执行 bash linux_json_api.sh <模块名>;
  3. 脚本按函数名分发,函数内部组合系统命令产生 JSON 输出;
  4. 退出码 0 → res.send(标准输出原文);非 0 → res.sendStatus(500)。

PHP 路径下则由 app/server/index.php 以 shell_exec 调同一个脚本,语义相同但无 500 分支(脚本失败时返回空体 200,见第七章问题 4 的路径差异说明)。

四、认证与首次调用(curl 实测)

本章以服务器甲为基准,从无认证直连到带认证调用逐层实测,形成可复制的首次调用范式。

4.1 无认证直连(本机 80 端口)

先看完整响应头,确认响应约定:

curl -s -i 'http://127.0.0.1/server/?module=general_info'
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 181
ETag: W/"b5-qavX07TACtcqMOSShT9XEyYzAUE"
Date: Fri, 23 Oct 2026 18:05:20 GMT
Connection: keep-alive
Keep-Alive: timeout=5

{ "OS": "Ubuntu 22.04.5 LTS 6.8.0-138-generic", "Hostname": "linuxdash-node", "Uptime": " 4 days 2 hours 17 minutes and 23 seconds ", "Server Time": "Fri Oct 23 18:05:20 UTC 2026" }

确认两个关键点:Content-Type 是 text/html; charset=utf-8 而非 application/json;响应体是脚本原样输出(含空格排版),消费端自行解析。

4.2 经反向代理 + HTTP Basic 认证调用

生产部署建议把面板藏在 nginx 反代之后并加 Basic 认证(账号 admin、密码 q1w2e3r4,htpasswd 生成命令见 《Ubuntu 22.04 安装 linux-dash 指南》)。无凭据、错误凭据、正确凭据三种场景实测:

curl -s -i 'http://127.0.0.1:8080/server/?module=load_avg' | head -8
HTTP/1.1 401 Unauthorized
Server: nginx/1.18.0 (Ubuntu)
Date: Fri, 23 Oct 2026 18:15:02 GMT
Content-Type: text/html
Content-Length: 188
Connection: keep-alive
WWW-Authenticate: Basic realm="Linux Dash Admin"
curl -s -o /dev/null -w '%{http_code}\n' -u 'admin:wrongpass' 'http://127.0.0.1:8080/server/?module=load_avg'
401
curl -s -i -u 'admin:q1w2e3r4' 'http://127.0.0.1:8080/server/?module=load_avg'
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Fri, 23 Oct 2026 18:15:11 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 65
Connection: keep-alive
X-Powered-By: Express
ETag: W/"41-iCmz2mkZUAZoS1ZxIYoekoYHXes"

{ "1_min_avg": 11.1667, "5_min_avg": 15.0833, "15_min_avg": 17.5}

也可以不使用 curl 的 -u 参数,直接构造 Authorization 头(admin:q1w2e3r4 的 Base64 为 YWRtaW46cTF3MmUzcjQ=):

curl -s -o /dev/null -w '%{http_code}\n' -H 'Authorization: Basic YWRtaW46cTF3MmUzcjQ=' 'http://127.0.0.1:8080/server/?module=load_avg'
200

五、各 API 域详解

本章按资源域逐个实测 29 个模块。除标注外,命令与回显均取自服务器甲(依赖完整环境)。回显是某一时刻的真实快照,其中的数值(负载、内存、进程 PID 等)在读者环境中必然不同;字段结构与怪癖才是可迁移的部分。

5.1 系统信息域

本域两个模块回答「这是一台什么服务器、跑了多久」。

general_info —— 系统概要。数据来源:lsb_release -ds(发行版名)、uname -r(内核)、hostname、/proc/uptime(换算为天时分秒)、date。

curl -s 'http://127.0.0.1/server/?module=general_info'
{ "OS": "Ubuntu 22.04.5 LTS 6.8.0-138-generic", "Hostname": "linuxdash-node", "Uptime": " 4 days 2 hours 17 minutes and 23 seconds ", "Server Time": "Fri Oct 23 18:05:20 UTC 2026" }

字段解读:

字段含义备注
OS发行版名 + 内核版本,两段拼接lsb_release 缺失时只剩内核串(第七章问题 3 实测)
Hostname主机名
Uptime天/时/分/秒格式化的开机时长取自 /proc/uptime,注意是系统开机时长,不是面板进程运行时长
Server Time服务器本地时间(date 输出)

number_of_cpu_cores —— 内部辅助函数,正常安装时无输出(仅当 /proc/cpuinfo 读不到 processor 时才输出 cannot be found):

curl -s 'http://127.0.0.1/server/?module=number_of_cpu_cores'; echo
(空响应,HTTP 200)

前端没有任何页签调用它——它只被 load_avg 在脚本内部间接使用(load_avg 自己直接读 /proc/cpuinfo 数核心,实测两处一致)。调用它仅用于确认脚本分发机制正常。

5.2 CPU 域

cpu_info —— lscpu 全量键值对。输出很长,以下为实测节选(首尾截取):

curl -s 'http://127.0.0.1/server/?module=cpu_info'

输出节选(实测首尾):

{ "Architecture": " x86_64", "CPU op-mode(s)": " 32-bit, 64-bit", "Address sizes": " 45 bits physical, 48 bits virtual", "Byte Order": " Little Endian", "CPU(s)": " 12", "On-line CPU(s) list": " 0-11", "Vendor ID": " GenuineIntel", "Model name": " Intel(R) Core(TM) i7-14700KF", "CPU family": " 6", "Model": " 183", "Thread(s) per core": " 1", "Core(s) per socket": " 12", ... "Vulnerability Spectre v2": " Mitigation; IBRS; IBPB conditional; STIBP disabled; RSB filling; PBRSB-eIBRS Not affected; BHI SW loop, KVM SW loop", ... "Vulnerability Vmscape": " Not affected", "Vulnerability Tsa": " Not affected", "Vulnerability Tsx async abort": " Not affected" }

字段即 lscpu 原生输出行(键=冒号前的标签,值=冒号后的内容,值首部带一个空格是原样保留的)。注意内核安全缓解(Vulnerability 系列)行也会一并返回,字段数随内核版本浮动。

cpu_utilization —— CPU 利用率,脚本内对 /proc/stat 做间隔 1 秒的两次采样,(1000×(非空闲增量)/总增量+5)/10 四舍五入为整数百分比,响应体是一个裸数字(无引号、无键名):

curl -s 'http://127.0.0.1:80/server/?module=cpu_utilization'; echo
13

同一时刻另一台负载形态不同的服务器取值不同(数值型语义不变)。解析时按「纯文本整数=百分比」处理。

load_avg —— 1/5/15 分钟负载均值。注意它不是 /proc/loadavg 的原值:脚本把每个负载乘 100 再除以核心数,得到「满载=100」的归一化百分比:

curl -s 'http://127.0.0.1/server/?module=load_avg'
{ "1_min_avg": 11.1667, "5_min_avg": 15.0833, "15_min_avg": 17.5}

换算关系:原始负载 = 数值 ÷ 100 × 核心数。以上述回显的 12 核机器为例,1_min_avg: 11.1667 对应原始 1 分钟负载 ≈ 1.34(11.1667/100×12),即「满载一台 12 核机器时该字段≈100」。字段即 ($1*100)/核心数 的结果,保留 4 位小数。

cpu_temp —— CPU 温度,依赖 lm-sensors 包的 sensors 命令(Intel 取 coretemp、AMD 取 k10temp 分支解析)。未安装 sensors 时返回空数组而非报错(这是最容易误判「模块坏了」的场景):

curl -s 'http://127.0.0.1/server/?module=cpu_temp'
[]

装上 lm-sensors 并 sensors-detect 识别到核心温度源后,同一端点返回整数摄氏度。

cpu_intensive_processes —— 按 CPU、内存、虚拟内存降序取前 15 个进程:

curl -s 'http://127.0.0.1/server/?module=cpu_intensive_processes'
[ { "pid": 5081, "user": "root", "cpu%": 0.0, "rss": 35972, "vsz": 1036528, "cmd": "PM2"}, { "pid": 4216, "user": "root", "cpu%": 0.0, "rss": 27976, "vsz": 1031496, "cmd": "node"}, { "pid": 10163, "user": "root", "cpu%": 0.0, "rss": 9460, "vsz": 19428, "cmd": "curl"}, { "pid": 10164, "user": "root", "cpu%": 0.0, "rss": 3616, "vsz": 4628, "cmd": "linux_json_api."}, { "pid": 10179, "user": "root", "cpu%": 0.0, "rss": 3624, "vsz": 8232, "cmd": "awk"}, { "pid": 10157, "user": "root", "cpu%": 0.0, "rss": 3336, "vsz": 4364, "cmd": "bash"}, { "pid": 10177, "user": "root", "cpu%": 0.0, "rss": 2940, "vsz": 7072, "cmd": "ps"}, { "pid": 4833, "user": "www-data", "cpu%": 0.0, "rss": 1612, "vsz": 55580, "cmd": "nginx"}, ... ]

字段解读:

字段含义单位
pid进程号—
user属主—
cpu%CPU 占用(ps axo pcpu)%
rss常驻内存KB
vsz虚拟内存KB
cmd命令名(comm 列,15 字符截断,如 linux_json_api.)—

回显中 curl/awk/bash/ps/linux_json_api. 一串正是本次 API 调用自身拉起的子进程链——该模块每次调用都会 fork 一条 bash → ps → awk 管道,监控低配机器时这也是被统计对象之一。

5.3 内存与磁盘域

current_ram —— 内存占用概要(/proc/meminfo 四个字段换算,单位 MB):

curl -s 'http://127.0.0.1/server/?module=current_ram'
{ "total": 32050.4, "used": 23448.4, "available": 8602 }

字段换算规则(脚本注释亦引用 proc 文档):total = MemTotal/1024;available = (MemFree + Buffers + Cached)/1024;used = total − available。注意这里 available 的口径与 free -m 的 available 列不完全相同(后者含 SReclaimable 等修正项),做容量告警阈值时建议以本端点口径为准建立基线。

memory_info —— /proc/meminfo 全文键值化,字段量约 50+,实测节选(首尾):

curl -s 'http://127.0.0.1/server/?module=memory_info'

输出节选(实测首尾):

{,"MemTotal": "       32819628 kB",,"MemFree": "         1273604 kB",,"MemAvailable": "   10093460 kB",,"Buffers": "          470700 kB",,"Cached": "          7396628 kB",,"SwapCached": "        91776 kB",,"Active": "         12132432 kB",,"Inactive": "       16144532 kB", ... ,"HugePages_Total": "       0",,"HugePages_Free": "        0", ...,"DirectMap1G": "    19922944 kB",}

⚠️ 注意这个输出的怪癖:{ 后有前导逗号、字段间是双逗号、结尾 ,}——这是脚本对 /proc/meminfo 的空行也追加逗号导致的,原始响应不是严格合法 JSON。消费端需先做容错清洗(如压缩 ,,→,、剥首尾逗号)再 JSON.parse。

swap —— 交换分区/交换文件列表(/proc/swaps),无交换设备时返回 []:

curl -s 'http://127.0.0.1/server/?module=swap'
[ { "filename": "/swapfile", "type": "file", "size": "2097148", "used": "2096360", "priority": "-2"} ]

字段单位 KB(/proc/swaps 原值),type 取值为 partition/file。

disk_partitions —— df -Ph 人类可读口径:

curl -s 'http://127.0.0.1/server/?module=disk_partitions'
[ {"file_system": "overlay", "size": "786G", "used": "518G", "avail": "234G", "used%": "69%", "mounted": "/"}, {"file_system": "tmpfs", "size": "64M", "used": "0", "avail": "64M", "used%": "0%", "mounted": "/dev"}, {"file_system": "shm", "size": "64M", "used": "0", "avail": "64M", "used%": "0%", "mounted": "/dev/shm"}, {"file_system": "/dev/sda3", "size": "786G", "used": "518G", "avail": "234G", "used%": "69%", "mounted": "/etc/hosts"}, {"file_system": "tmpfs", "size": "4.0K", "used": "0", "avail": "4.0K", "used%": "0%", "mounted": "/proc/acpi"} ]

字段与 df -Ph 一一对应。注意挂载点很多时(bind mount、快照等)返回条目会显著变多,容量告警应按 mounted 过滤目标路径。

io_stats —— /proc/diskstats 中读写计数非零的块设备,实测节选(首尾):

curl -s 'http://127.0.0.1/server/?module=io_stats'

输出节选(实测首尾):

[ { "device": "loop0", "reads": "15", "writes": "0", "in_prog.": "0", "time": "2"}, { "device": "loop1", "reads": "95", "writes": "0", "in_prog.": "0", "time": "62"}, ... { "device": "sda", "reads": "23515313", "writes": "241979356", "in_prog.": "0", "time": "11332035"}, { "device": "sda1", "reads": "39", "writes": "0", "in_prog.": "0", "time": "7"}, ... { "device": "loop15", "reads": "74", "writes": "0", "in_prog.": "0", "time": "7"} ]

字段解读:reads/writes 为读/写完成总次数(自开机累计,非速率);in_prog. 为进行中的 I/O 请求数;time 为累计耗时(毫秒)。累计值做差才能得到速率。

⚠️ 常见误解澄清:io_stats 不依赖 sysstat 包——它直接读内核 /proc/diskstats,装不装 iostat/sar(sysstat 提供)都不影响本端点。缺依赖会失败的端点清单见第七章问题 1 的对照表。

5.4 网络域

bandwidth —— 各网口自开机以来的累计收发字节数(读 /proc/net/dev):

curl -s 'http://127.0.0.1/server/?module=bandwidth'
[,{ "interface": "lo:", "tx": 123745, "rx": 123745 },,{ "interface": "eth0:", "tx": 139783750, "rx": 1555161 },]

两个实测确认的怪癖:

  1. tx/rx 标签互换:脚本把 /proc/net/dev 第 2 列(实际是收字节数 rx_bytes)标成了 tx,把第 10 列(发字节数 tx_bytes)标成了 rx。与同时刻 /proc/net/dev 原值对照可验证——
cat /proc/net/dev | grep eth0
  eth0: 139785094   25720    0    0    0     0          0         0  1556505   20246    0    0    0     0       0          0

原值第 2 列 = 139785094(收),第 10 列 = 1556505(发);而 API 返回 tx: 139783750, rx: 1555161——数值增长方向证明 tx 里装的是收字节、rx 里装的是发字节。做流量监控时请按此修正语义。 2. 接口名带冒号(lo:、eth0:)且 JSON 中夹着空逗号(同 memory_info 的清洗问题)。

download_transfer_rate / upload_transfer_rate —— 每网口读两次字节计数(间隔 1 秒)求差,得到 KB/s 瞬时速率:

curl -s 'http://127.0.0.1:80/server/?module=download_transfer_rate'
{ "eth0": 0, "lo": 0}
curl -s 'http://127.0.0.1:80/server/?module=upload_transfer_rate'
{ "eth0": 0, "lo": 0}

空闲服务器上两值常为 0(差值 < 1KB 被整除截断)。字段键=网口名,值=KB/s(整数)。因为内部 sleep 1,每次调用固定耗时约 2 秒(实测见 6.3 节),做自动化采集时要预留超时。

ip_addresses —— 网口 IP + 外网出口 IP(dig +short myip.opendns.com @resolver1.opendns.com):

curl -s 'http://127.0.0.1/server/?module=ip_addresses'

服务器甲(ifconfig 已装、dig 未装):

[,{"interface" : "eth0", "ip" : "10.89.57.2"}, ,{"interface" : "lo", "ip" : ""}, ,{ "interface": "external", "ip": "" } ]

服务器乙(ifconfig 已装、mawk、dig 未装):

[{"interface" : "eth0", "ip" : ""}, {"interface" : "lo", "ip" : ""}, { "interface": "external", "ip": "" } ]

服务器丙(ifconfig、dig 均未装):

[,{ "interface": "external", "ip": "" } ]

三个回显正好构成依赖影响谱系:无 ifconfig(net-tools 包)→ 内网口条目整个消失;awk 是 mawk(不支持 gawk 的三参数 match())→ 内网口 IP 提取为空串;无 dig(dnsutils/bind9-dnsutils 包)→ external 条目 IP 为空。要让该端点完整出数,需要同时装 net-tools、bind9-dnsutils,并保证 awk 是 gawk。

network_connections —— netstat -ntu 的对端地址聚合计数:

curl -s 'http://127.0.0.1/server/?module=network_connections'
[,{ "connections": 1, "address": "127.0.0.1:55208" },,{ "connections": 14, "address": "127.0.0.1:80" },]

字段:connections=该对端地址(IP:端口)的连接条数,address=对端地址。依赖 netstat(net-tools 包),缺失时返回 [,](第七章问题 1 实测)。

arp_cache —— ARP 表:

curl -s 'http://127.0.0.1/server/?module=arp_cache'
[ { "addr": "ops", "hw_type": "ether", "hw_addr.": "4a:34:b9:53:ba:18", "mask": "eth0" } ]

字段对应 arp 命令列:地址、硬件类型、MAC(字段名 hw_addr. 带点号是脚本原始命名)、掩码/设备。依赖 arp(net-tools 包)。

ping —— 对 app/server/config/ping_hosts 清单里的目标逐个 ping -qc 2,取 rtt 平均值(毫秒)。本文实测环境的清单为国内可达目标(清单修改方法见 《linux-dash 配置参数详解》):

curl -s 'http://127.0.0.1/server/?module=ping'
[{"host": "baidu.com", "ping": 26.704 },{"host": "223.5.5.5", "ping": 20.494 }]

每次调用对每个目标发 2 个包并等待,目标数越多耗时越长(2 目标实测 2.08 秒)。目标不可达时对应主机不出现在返回中或 rtt 为空,排障时优先核对 ping_hosts 内容与 ICMP 出网策略。

5.5 进程与账户域

ram_intensive_processes —— 按内存占比降序前 15 进程(字段结构与 cpu_intensive_processes 相同,cpu% 换成 mem%):

curl -s 'http://127.0.0.1/server/?module=ram_intensive_processes'
[ { "pid": 5081, "user": "root", "mem%": 0.1, "rss": 35972, "vsz": 1036528, "cmd": "PM2"}, { "pid": 4216, "user": "root", "mem%": 0.0, "rss": 28052, "vsz": 1031496, "cmd": "node"}, { "pid": 10185, "user": "root", "mem%": 0.0, "rss": 9744, "vsz": 19428, "cmd": "curl"}, { "pid": 10202, "user": "root", "mem%": 0.0, "rss": 3596, "vsz": 8232, "cmd": "awk"}, ... ]

docker_processes —— 若服务器装有 docker 命令,则逐个列出 Docker 运行中对象内的进程(按 CPU 排序,字段含 cname 对象名)。未安装 docker 时返回空数组:

curl -s 'http://127.0.0.1/server/?module=docker_processes'
[ ]

⚠️ 该模块会以面板进程的身份调用 docker/docker top,若面板以非 root 用户运行且该用户不在 docker 组,模块同样拿不到数据。不需要 Docker 监控时建议直接禁用该模块(改名法见 《linux-dash 配置参数详解》)。

logged_in_users —— 当前登录会话(w -h):

curl -s 'http://127.0.0.1/server/?module=logged_in_users'
[ ]

无活动终端会话时为空数组;有人通过 SSH 登录后会返回 user/from/when 三字段条目。

recent_account_logins —— 最近一年登录记录(lastlog -t 365):

curl -s 'http://127.0.0.1/server/?module=recent_account_logins'
[ ]

同样无历史登录时为空数组。字段为 user/ip/date(年+月+日+时分)。数据源是 /var/log/lastlog,清空该文件的系统会一直返回空。

user_accounts —— /etc/passwd 全量账户,UID≤499 标记为 system、其余标记为 user:

curl -s 'http://127.0.0.1/server/?module=user_accounts'

输出节选(实测首尾):

[ { "type": "system", "user": "root", "home": "/root" }, { "type": "system", "user": "daemon", "home": "/usr/sbin" }, ... { "type": "user", "user": "nobody", "home": "/nonexistent" }, { "type": "system", "user": "_apt", "home": "/nonexistent" }, { "type": "system", "user": "syslog", "home": "/home/syslog" } ]

注意 nobody(UID 65534)被标成了 user——499 的分界线沿用了老版 Debian 的 uid 语义,Modern 系统里它是匿名系统账户,做账户审计时需要单独排除。

5.6 应用与任务域

common_applications —— 对 php/node/mysql/mongo/vim/python/ruby/java/apache2/nginx/openssl/vsftpd/make 共 13 个常用程序做 whereis 探测:

curl -s 'http://127.0.0.1/server/?module=common_applications'
[ { "binary": "php", "location": "", "installed": false }, { "binary": "node", "location": " /usr/bin/node /usr/include/node", "installed": true }, { "binary": "mysql", "location": "", "installed": false }, { "binary": "mongo", "location": "", "installed": false }, { "binary": "vim", "location": " /usr/share/vim", "installed": true }, { "binary": "python", "location": "", "installed": false }, { "binary": "ruby", "location": "", "installed": false }, { "binary": "java", "location": "", "installed": false }, { "binary": "apache2", "location": "", "installed": false }, { "binary": "nginx", "location": " /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx", "installed": true }, { "binary": "openssl", "location": " /usr/bin/openssl", "installed": true }, { "binary": "vsftpd", "location": "", "installed": false }, { "binary": "make", "location": "", "installed": false } ]

installed 判定依据是 whereis 第二列是否为空——它探测的是文件名存在性,不能证明对应服务可用(如装了 mysql 客户端但没装 server 也会显示 installed)。

memcached —— 向 127.0.0.1:11211 发 stats 取字节数指标。本机无 memcached 服务、也未装 nc 时返回畸形体 {,}:

curl -s 'http://127.0.0.1/server/?module=memcached'
{,}

装齐 nc + 运行 memcached 后,该端点返回 memcached stats 输出中 bytes 相关字段的键值统计。{,} 是典型的「依赖缺失但 HTTP 仍 200」形态,见第七章问题 5。

redis —— redis-cli INFO 过滤 6 项指标(redis_version、connected_clients、connected_slaves、used_memory_human、total_connections_received、total_commands_processed)。无 redis-cli 时返回空对象 { }:

curl -s 'http://127.0.0.1/server/?module=redis'
{ }

Redis 带密码时需把口令写进脚本内嵌常量 redisPassword(写法与安全注意见 《linux-dash 配置参数详解》)。

pm2_stats —— 解析 pm2 list 表格。⚠️ 实测确认:该模块按老版 pm2 的固定列位解析(第 2/4/6/8…列),本文实测的 pm2 7.1.0 表格列位已变化,解析结果是错位的垃圾 JSON:

curl -s 'http://127.0.0.1/server/?module=pm2_stats'
[ { "appName":"metrics", "id":"cpu:", "mode":"|", "pid":"usage:", "status":"|", "restart":"⇓", "uptime":"⇑", "memory":"/68.87%", "watching":"68.87%" } ]

真实 pm2 应用名并不是 metrics,status/restart 等字段值也是表头装饰字符——列位错位导致取到了错误的列。脚本假定的固定列位只在老版 pm2 的表格输出下成立,新版 pm2 用户建议禁用该模块(见第七章问题 6)。未安装 pm2 时该模块正常返回 [](空数组,脚本对「无 pm2」做了保护)。

scheduled_crons —— 汇总 /etc/crontab、/etc/cron.d/* 与各用户 crontab。依赖 gawk(脚本用了 gawk 特有的 gensub)。mawk 环境实测返回空响应体 + HTTP 200:

curl -s -w '\nHTTP:%{http_code}\n' 'http://127.0.0.1/server/?module=scheduled_crons' | head -4

HTTP:200

(服务器乙/丙,awk 为 mawk)装 gawk 后(服务器甲)可出数,但输出带前导逗号与 , 前缀命令等怪癖,实测节选(首部):

[,{ "min": "25", "hrs": "6",  "day": "*",  "month": "*",  "wkday": "*",  "user": "root",  "CMD": ",/etc/cron.daily/apt-compat " },,{ "min": "25", "hrs": "6",  "day": "*",  "month": "*",  "wkday": "*",  "user": "root",  "CMD": ",/etc/cron.daily/dpkg " },,{ "min": "25", "hrs": "6",  "day": "*",  "month": "*",  "wkday": "*",  "user": "root",  "CMD": ",/etc/cron.daily/logrotate " },,{ "min": "30", "hrs": "3",  "day": "*",  "month": "*",  "wkday": "0",  "user": "root",  "CMD": ",test -e /run/systemd/system || SERVICE_MODE=1 /usr/lib/x86_64-linux-gnu/e2fsprogs/e2scrub_all_cron " },,{ "min": "10", "h

字段为 crontab 五个时间位 + user + CMD。CMD 里 run-parts 展开的路径前带逗号、条目间夹双逗号——同 memory_info,消费端需容错清洗。

cron_history —— 从 /var/log/syslog 抓最近 50 条 CRON 日志。依赖 gawk + rsyslog 产生的 syslog;无 syslog 或无 CRON 记录时返回 []:

curl -s 'http://127.0.0.1/server/?module=cron_history' | head -c 400; echo
[]

(实测环境未跑 rsyslog,暂无历史可抓;按脚本定义,有日志的环境返回 time/user/message 三字段的条目数组。)

5.7 响应耗时实测汇总

自动化消费这些端点前,先建立耗时预期(curl -w '%{time_total}' 实测,服务器甲):

模块实测耗时原因
load_avg / current_ram / disk_partitions0.012–0.013 s单次读 procfs
memory_info0.081 sawk 全文处理
cpu_utilization2.013 s内部两次采样各 sleep 1
download_transfer_rate2.019 s每网口 sleep 1
upload_transfer_rate2.018 s每网口 sleep 1
ping2.081 s每目标 ping 2 包等待

验证命令示例(以 cpu_utilization 为例):

curl -s -o /dev/null -w 'cpu_utilization: %{time_total}s\n' 'http://127.0.0.1/server/?module=cpu_utilization'
cpu_utilization: 2.012917s

结论:带内部 sleep 1 的模块单次调用 ≥2 秒,前端却按 1–1.5 秒间隔轮询(见第六章),调用方自建脚本时应设置 ≥3 秒超时并接受错峰返回。

5.8 WebSocket 通道实测

REST 之外,服务端在 /websocket 挂了 WebSocket 通道:客户端握手后发送模块名明文,服务端以 { "moduleName": "...", "output": "..." } 回推。用 Node.js websocket 库写探针实测(探针脚本思路:连接 ws://127.0.0.1:80/websocket,发送模块名,原样打印响应并尝试 JSON 解析):

纯数字输出模块(cpu_utilization,响应体不含引号):

RAW    : { "moduleName": "cpu_utilization", "output": "13" }
PARSE OK, output = 13

含引号输出模块(load_avg,响应体内嵌 JSON):

RAW    : { "moduleName": "load_avg", "output": "{ "1_min_avg": 12.5833, "5_min_avg": 16.75, "15_min_avg": 18.25}" }
JSON.parse FAILED: Expected ',' or '}' after property value in JSON at position 42

根因在服务端 index.js 的响应拼接源码(实测读取):

var wsResponse = '{ "moduleName": "' + moduleName + '", "output": "'+ output.join('') +'" }'
wsClient.sendUTF(wsResponse)

模块输出被未转义地拼进 JSON 字符串字面量——输出一含双引号(绝大多数模块的输出都含),外层 JSON 即非法,前端 JSON.parse(event.data) 直接抛错。实测结论:只有输出为纯数字的模块(cpu_utilization 等)能在 WebSocket 通道正常工作,其余模块全部依赖 REST 通道取数。这也解释了为什么面板大部分数据仍能显示——前端 server 服务对 ws 失败的模块会走 REST 兜底(分流逻辑见 6.1 节)。

六、轮询间隔与前端刷新关系

本章回答两个问题:前端哪些插件在轮询、以什么间隔轮询;API 端点耗时与轮询间隔叠加后实际的数据新鲜度是多少。

6.1 前端取数分流逻辑

前端 src/js/core/server.service.js 的取数顺序(源码实测读取):

  1. 启动时 GET /websocket 探测服务端支持;
  2. 浏览器与服务端都支持 → 建立 WebSocket 连接(ws(s)://主机:端口);
  3. server.get(模块名, 回调) 时:ws 连接就绪 → 发送模块名等推送;ws 未就绪或未建立 → GET server/?module=<模块名> REST 兜底;
  4. ws 推送到达时前端做两次 JSON.parse(先解析外层 {"moduleName":...,"output":"..."},再解析 output 字段)——第二段解析遇引号即失败(5.8 节根因)。

6.2 各插件的轮询间隔

轮询只发生在图表类插件(源码中通过 AngularJS $interval(getData, refreshRate) 实现);表格与键值类插件只在页面加载时取一次数,不轮询。逐文件实测读取 src/js/ 的声明:

插件(页签)模块声明的 refresh-rate实际刷新节奏
ramChart(System Status)current_ram1000 ms约 1 秒一次
cpuUtilizationChart(System Status)cpu_utilization1500 ms约 1.5 秒一次
cpuTemp(System Status)cpu_temp1500 ms约 1.5 秒一次
cpuAvgLoadChart(System Status)load_avg未声明走多折线基类默认 1000 ms
downloadTransferRateChart(Network)download_transfer_rate未声明默认 1000 ms
uploadTransferRateChart(Network)upload_transfer_rate未声明默认 1000 ms
其余全部表格/键值插件(Basic Info / Network 表格 / Accounts / Apps 等)——仅页面加载时取一次,刷新需重载页签

基类缺省值依据(multi-line-chart-plugin.directive.js 源码实测读取):

var refreshRate = (angular.isDefined(scope.refreshRate)) ? scope.refreshRate : 1000

6.3 轮询间隔 × 端点耗时 = 实际新鲜度

把 6.2 的间隔与 5.7 的端点耗时叠加,得到真实数据节奏:

模块轮询间隔端点耗时实际效果
current_ram1000 ms0.012 s1 秒一刷,节奏准确
load_avg1000 ms0.012 s1 秒一刷,节奏准确
cpu_utilization1500 ms2.013 s请求互相重叠,实际约 2–3.5 秒一刷
cpu_temp1500 ms极快(无 sensors 时立即返回 [])1.5 秒一刷
download/upload_transfer_rate1000 ms2.02 s请求互相重叠,实际约 2–3 秒一刷

⚠️ 服务端并发堆积风险:每次 REST 调用都 spawn 一条 bash 子进程,而 cpu_utilization/download/upload 每次要跑 2 秒以上、前端却每 1–1.5 秒发一次——请求会重叠排队。实测在 5.2 节进程快照里可以直接看到同一时刻并存的 curl/awk/bash/linux_json_api. 子进程链。低配服务器或浏览器多开页签时,建议通过禁用对应插件或拉长 refresh-rate 源码常量来降载(改法见 《linux-dash 配置参数详解》)。

6.4 外部程序化采集的推荐姿势

绕开前端直接采集 API 时,按以下口径最稳(均为本文实测结论):

  • 全部走 REST(GET /server/?module=),不依赖 WebSocket 通道(5.8 节缺陷);
  • 不信任 Content-Type,对响应体先做逗号清洗再 JSON.parse(memory_info/scheduled_crons/bandwidth 的怪癖);
  • cpu_utilization 按纯文本整数解析(无 JSON 包裹);
  • bandwidth 的 tx/rx 语义互换需修正(5.4 节);
  • 对带 sleep 的端点设置 ≥3 秒超时,采集间隔 ≥5 秒;
  • Invalid module 响应也是 HTTP 200,需按响应体内容判失败(第七章问题 7)。

💡 技术拓展:程序化读取主机指标时,linux-dash 这类「面板自带 API」与专业采集方案的取舍——

方案数据面消费方式适用
linux-dash /server API29 个主机模块HTTP GET 即取快速搭建告警小脚本
node_exporter + Prometheus全量主机指标 + 时序库PromQL 拉取正式监控体系
glances Web 模式 / RESTful API主机+进程+传感器HTTP JSON单机深度指标(参见 《glances 介绍与选型指南》)
终端 TUI 自读面向人眼无 API(参见 《WTFUtil 介绍与选型指南》)人工盯屏

本文场景为「已有 linux-dash 面板,想复用其端点做轻量采集」,选 /server API 即可;要长期时序留存则应上 Prometheus 体系。

七、常见问题(排障实录)

linux-dash 的模块失败形态有个统一规律:几乎从不返回 HTTP 错误码,而是返回空体、空数组或畸形 JSON——排障第一动作永远是看响应体而不是状态码。本章每条都是实测现象与修复。

问题 1:哪些模块依赖哪些命令?缺了会返回什么?

三类环境(依赖完整/仅 mawk/裸系统)逐端点对照实测,缺失依赖时的响应形态汇总:

缺失依赖(所属包)受影响模块实测响应形态(HTTP 200)实测环境
netstat(net-tools)network_connections[,]服务器丙
arp(net-tools)arp_cache[ ]服务器丙
ifconfig(net-tools)ip_addresses内网口条目消失,只剩 [,{ "interface": "external", "ip": "" } ]服务器丙
dig(dnsutils/bind9-dnsutils)ip_addressesexternal 条目 IP 为空串服务器甲
gawk(awk 非 gawk)scheduled_crons空响应体服务器乙/丙
gawk(awk 非 gawk)cron_history[]服务器乙/丙
sensors(lm-sensors)cpu_temp[]服务器甲
lsb_release(lsb-release)general_infoOS 字段只剩内核串 6.8.0-138-generic服务器丙
redis-cli(redis-tools)redis{ }服务器甲/丙
nc(netcat-openbsd 等)memcached{,}服务器甲/丙
docker 命令docker_processes[] / [ ]服务器甲/丙
pm2(npm 包)pm2_stats[](模块对无 pm2 有保护,正常空数组)服务器丙

修复方式统一:apt install <对应包>(如 apt install net-tools bind9-dnsutils gawk lsb-release lm-sensors redis-tools),装完无需重启面板服务——脚本每次调用都重新执行,下一次请求立即生效。验证(服务器丙补装前后的对比,以 network_connections 为例):

# 补装前
curl -s 'http://127.0.0.1/server/?module=network_connections'
[,]
apt install net-tools
# 补装后复测
curl -s 'http://127.0.0.1/server/?module=network_connections'
[,{ "connections": 1, "address": "127.0.0.1:45598" },,{ "connections": 1, "address": "127.0.0.1:80" },]

无需重启任何服务,补装后第一次请求即出真实连接数据。

⚠️ 再次澄清:io_stats 不依赖 sysstat(读 /proc/diskstats),「装 sysstat 才有磁盘 IO 数据」是常见误解;sysstat 的 sar/iostat 是另一套独立工具。

问题 2:ip_addresses 出来的内网 IP 全是空串

现象:接口条目在、ip 字段全是 ""(服务器乙实测回显见 5.4 节)。 定位:脚本用 gawk 的三参数 match($0, /inet (addr:)?([0-9.]*)/, a) 提取 IP,Ubuntu 22.04 默认 awk 是 mawk,不支持三参数 match,a[2] 恒为空。 解决:apt install gawk 让 /usr/bin/awk 指向 gawk(alternatives 自动切换),复测:

apt install gawk
curl -s 'http://127.0.0.1/server/?module=ip_addresses'

服务器甲(gawk 已装)同端点即能取出 10.89.57.2 一类的真实地址。同理,scheduled_crons 空响应体的第一嫌疑也是 mawk 缺 gensub。

问题 3:general_info 的 OS 字段只剩一串内核号

现象(服务器丙实测):

{ "OS": "6.8.0-138-generic", "Hostname": "linuxdash-sysd", "Uptime": " 4 days 2 hours 32 minutes and 44 seconds ", "Server Time": "Fri Oct 23 18:20:40 UTC 2026" }

定位:OS 字段由 lsb_release -ds 的输出与 uname -r 拼接;最小化系统没装 lsb-release 包,前半段为空。 解决:apt install lsb-release,复测:

apt install lsb-release
curl -s 'http://127.0.0.1/server/?module=general_info'
{ "OS": "Ubuntu 22.04.5 LTS 6.8.0-138-generic", "Hostname": "linuxdash-sysd", "Uptime": " 4 days 2 hours 43 minutes and 36 seconds ", "Server Time": "Fri Oct 23 18:31:32 UTC 2026" }

OS 字段恢复为「发行版名 + 内核号」完整形态,同样无需重启面板服务。

问题 4:调用返回 Internal Server Error(HTTP 500)

现象:任意模块都 500,或个别模块 500。实测复现(临时把脚本写成非法 bash 语法):

curl -s -w '\nHTTP:%{http_code}\n' 'http://127.0.0.1/server/?module=load_avg'
Internal Server Error
HTTP:500

定位:这是唯一返回 5xx 的场景——linux_json_api.sh 自身语法损坏(手工改模块时漏了引号/括号、或禁用模块时把函数体注释错位,见 《linux-dash 配置参数详解》 的模块开关章节),bash 解析失败退出码非 0,Node 端 res.sendStatus(500)。 解决:恢复脚本语法。可先用语法检查定位:

bash -n /opt/linux-dash/app/server/linux_json_api.sh && echo SYNTAX-OK
SYNTAX-OK

语法正确后无需重启服务,下一次请求即恢复 200(本文实测恢复后立即取到正常数据)。

⚠️ PHP 路径无此 500 分支:shell_exec 拿到空输出照样返回 200 空体,故障更隐蔽,排障时更要看响应体。

问题 5:模块返回 {,}、{ } 这类畸形体但状态码 200

现象与定位(实测):memcached 返回 {,} 是本机无 nc/无 memcached 服务;redis 返回 { } 是无 redis-cli。它们是脚本里 nc | grep | awk 管道空转后拼出来的残缺 JSON。 解决:不需要对应中间件监控就禁用模块(改名法,如把函数 redis 改名为 _redis_off,见 《linux-dash 配置参数详解》);需要则装依赖并确保服务监听 127.0.0.1 对应端口(memcached 默认 11211)。

问题 6:pm2_stats 返回的字段值明显不对

现象(服务器甲,pm2 7.1.0 实测回显见 5.6 节):appName 变成 metrics、status 是 |、memory 是 /68.87% 之类的错位值。 定位:脚本按老版 pm2 表格的固定列号(第 2/4/6 列等偶数列)切片,新版 pm2 表头与列宽变了,切出来全是错位列。 解决:使用列位与脚本假定匹配的老版 pm2 可恢复;或禁用 pm2_stats 模块;或在脚本里改用 pm2 jlist(JSON 输出)重写该函数——注意改完先 bash -n 过语法(问题 4)。

问题 7:自定义模块名/非法模块名返回什么?

实测三类输入:

curl -s 'http://127.0.0.1/server/?module=notexist'; echo
curl -s 'http://127.0.0.1/server/?module='; echo
curl -s 'http://127.0.0.1/server/?module=internet_speed'; echo
{\"success\":false,\"status\":\"Invalid module\"}
{\"success\":false,\"status\":\"Invalid module\"}
{\"success\":false,\"status\":\"Invalid module\"}

三点结论:① 未知模块 HTTP 仍 200,程序化消费必须按响应体判失败;② 响应体里的引号是带反斜杠的字面量(od -c 验证),它本身不是合法 JSON;③ internet_speed 是前端源码里定义了但从未挂到任何页签的死插件,服务端无此函数,恒返回 Invalid module。

问题 8:哪些模块在偷偷执行外部命令?安全边界在哪

服务端把 module 参数直接当作 bash 函数名分发(type -t $fnCalled 校验为函数才执行),任意函数名以外输入都落到 Invalid module,无注入面。但要注意:面板进程对模块脚本的调用权限就是面板服务自身的权限——以 root 跑 Node/Apache 时,docker_processes、user_accounts、scheduled_crons 等都会以 root 视角出全量数据;反代 Basic 认证(第四章)因此不是可选项而是必选项。生产建议:面板降权运行 + 反代认证 + 不需要的模块改名禁用。

问题 9:如何快速验证 API 整体健康

一条命令巡检核心端点(状态码 + 关键字段),实测输出:

curl -s -o /dev/null -w 'general_info: %{http_code}\n' 'http://127.0.0.1/server/?module=general_info'
curl -s -o /dev/null -w 'load_avg: %{http_code}\n' 'http://127.0.0.1/server/?module=load_avg'
curl -s -o /dev/null -w 'current_ram: %{http_code}\n' 'http://127.0.0.1/server/?module=current_ram'
curl -s -o /dev/null -w 'websocket: %{http_code}\n' 'http://127.0.0.1/websocket'
general_info: 200
load_avg: 200
current_ram: 200
websocket: 200

四个 200 说明服务端分发链正常;若出现 500 回到问题 4 查脚本语法,若某模块 200 但内容为空/畸形回到问题 1、5 查依赖。

八、参考链接