服务启停页面,右上角跳出"获取失败"。 三个服务的状态,全部停在"检测中"。 点启动、点停止------没有任何反应。
所有按钮集体沉默。原因? 一行代码:
var h = s.hermes, o = s.openclaw;------漏了w = s.ws。
事故现场
给配置中心加了一个新服务:WS(消息网关)。
服务启停页面新增一行:WS(消息网关) [启动] [停止]。
刷新页面------右上角绿色横幅变成红色:
● 获取失败
三个服务状态全部停在初始值"检测中"。点任何一个"启动"按钮------页面纹丝不动。
排查:API 是好的
第一步怀疑后端。直接 curl 服务状态接口:
bash
curl http://localhost:8899/api/service-status
json
{"ok": true, "status": {"openclaw": false, "hermes": true, "ws": false}}
API 正常------三个服务的状态清清楚楚。
问题在前端。
根因:一个漏声明的变量
打开前端加载服务状态的函数:
javascript
function loadSvc(){
fetch('/api/service-status')
.then(r => r.json())
.then(function(d){
var s = d.services || d.status || {};
var h = s.hermes, o = s.openclaw; // ← 问题在这行
function setRow(tag, svc){
$(tag).textContent = svc ? '运行中' : '已停止';
}
setRow('tagHermes', h);
setRow('tagOpenclaw', o);
setRow('tagWs', w); // ← w 是什么?!
$('svcBadge').textContent = '● 服务状态已加载';
})
.catch(function(){
$('svcBadge').textContent = '● 获取失败'; // ← 从这里冒出来
});
}
新增 WS 服务时,状态读取写的是:
javascript
var h = s.hermes, o = s.openclaw;
忘了加上 w = s.ws。
于是执行到这一行:
javascript
setRow('tagWs', w); // w 未定义 → ReferenceError: w is not defined
抛异常 → .then 链中断 → 跳到 .catch → "获取失败"。
页面看起来是"获取失败",真相是:一个未声明的变量,中断了整个 Promise 链。
为什么"所有按钮没反应"?
按钮的 onclick 是独立的函数(svcAction),按理说不受 loadSvc 影响。
但用户感知的是:点按钮------没有反馈。
因为状态加载失败了:
- 状态标签停在"检测中"(loadSvc 没跑完,没更新)
- 按钮禁用状态没设置(运行中的服务,启动按钮应该置灰------现在全亮着)
- 点击后的 toast 提示、状态刷新,全部依赖 loadSvc 的成功回调
一个环节崩了,整个页面的"活着感"都没了。
修复:补上漏掉的变量
javascript
var h = s.hermes, o = s.openclaw, w = s.ws; // ← 补上 w
刷新------状态正常加载,按钮正常工作。
复盘:三个教训
1. "复制模板"式声明,是漏变量的温床。
javascript
var h = s.hermes, o = s.openclaw;
这种一行多变量的写法,新增一个服务时,最容易漏掉最后一个。
更安全:每个变量单独声明------或者,至少新增功能时,把整行重写一遍,而不是"在结尾加"。
2. .then 链的异常,会被 catch 吞成"假错误"。
vbnet
ReferenceError: w is not defined
→ .catch 显示"获取失败"
真正的 bug(w 未定义)被"获取失败"掩盖了。排查时第一反应是"后端挂了"------其实后端好好的。
异常链的 catch 只是兜底,不是诊断------真正的错误要看 console 的 ReferenceError。
3. 新增功能,必须全局搜索旧代码。
加一个 WS 服务,要改的不只是 HTML 那一行:
csharp
✅ 状态读取: var w = s.ws
✅ 状态渲染: setRow('tagWs', w)
✅ 按钮禁用: btnStartWs / btnStopWs
✅ 运行计数: 3个服务
漏了任何一个,页面就处于"半新半旧"的诡异状态。
新增一个功能,漏改一行代码------ 整个页面为你保持沉默。 而 Promise 链上的异常, 会把真正的 bug,悄悄翻译成一句"获取失败"。
(真实事故记录:配置中心新增 WS 服务,loadSvc 的状态读取漏写 w = s.ws,setRow 引用未定义变量 → ReferenceError 中断 Promise 链 → catch 显示"获取失败"→ 状态不加载、按钮无反馈。修复:补上变量声明。教训:一行多变量声明的漏写、catch 掩盖真实异常、新增功能需全局同步。)