# GHCS v0.2 终端排障 SOP(SSH Web Terminal Debug SOP) --- ## 1|本次问题的具体原因(复盘结论) ### 1.1 真正卡住不是一个 bug,而是三层叠加 1) **页面 200 ≠ 终端可用** - `/console/terminal` 返回 200 只说明 Next 页面渲染成功。 - 终端真正依赖:`GET /ws/terminal/servers` + `WS /ws/terminal/{server_key}`。 - 只要后端路由未挂载、或前端没打到正确后端,页面仍 200,但终端必失败。 2) **环境变量未生效 / [localhost](http://localhost) 解析导致“像玄学”** - `NEXT_PUBLIC_CONSOLE_API` 改了但未重启前端 → Next 继续用旧值。 - `localhost` 在部分环境可能走 IPv6(`::1`)而后端仅在 IPv4(`127.0.0.1`)监听 → 表现为偶发连不上 / 重试。 3) **焦点判断误区:光标渲染 ≠ 键盘输入通道** - xterm 光标是渲染状态,点别处后仍可能停在原位。 - 真正需要判断的是:键盘输入是否进入终端(用 `echo` 回显验证)。 ### 1.2 之前陷入的误区(导致一直修不动) - **误区 A:把“页面能打开”当成“后端都通了”** - **误区 B:用光标/感觉判断焦点**,而不是用命令回显判定输入通道 - **误区 C:改 `.env.local` 不重启前端**,导致“我明明改了但没变化” - **误区 D:一次改太多(前端/后端/依赖/配置一起动)**,失去最小证据链 ### 1.3 本次为什么修得顺利(方法) 把问题拆成 4 层,并且每层只用一个“最小证据”验收: - 后端活着:`/docs` 能开 - 路由挂载:`curl -i /ws/terminal/servers` 看 200/404 - 前端指向正确后端:`.env.local` + 重启 - 交互与焦点:`whoami / pwd / echo ...` 回显 --- ## 2|GHCS v0.2 终端排障 SOP(五段式,不跳步) ### Step 0|准备(两窗口) - 终端 A:backend(FastAPI) - 终端 B:frontend(Next.js) --- ### Step 1|确认后端在跑 ```bash cd ~/guanghu-dev/ghcs-mono/backend source venv/bin/activate python -m uvicorn main:app --host 127.0.0.1 --port 5002 --reload ``` 验收:浏览器打开 `http://127.0.0.1:5002/docs` --- ### Step 2|确认 terminal_router 已挂载(最关键一锤) ```bash curl -i http://127.0.0.1:5002/ws/terminal/servers ``` - **200 + JSON**:后端终端路由 OK - **404**:检查 `backend/main.py` 是否包含: - `from terminal_router import router as terminal_router` - `app.include_router(terminal_router)` --- ### Step 3|确认前端 API_BASE 指向正确,并且已重启生效 ```bash cd ~/guanghu-dev/ghcs-mono/frontend cat -n .env.local ``` 推荐: ``` NEXT_PUBLIC_CONSOLE_API=http://127.0.0.1:5002 ``` **改完必须重启前端**: ```bash npm run dev ``` --- ### Step 4|确认“页面可用”与“后端可达”不是一回事 打开:`http://localhost:3000/console/terminal` 验收点:服务器下拉是否能显示(来自 Step 2 的 servers 列表)。 --- ### Step 5|交互与焦点验收(只看回显,不看光标) 连接成功后输入: ```bash whoami pwd echo FOCUS_OK ``` 期望回显:用户名、路径、`FOCUS_OK` #### 5.1 点击聚焦验收(对应历史 bug) 1) 点页面别处 2) 点回黑框 3) 输入: ```bash echo CLICK_FOCUS_OK ``` 期望回显 `CLICK_FOCUS_OK` #### 5.2 额外:判断是否一直保持输入通道 点页面别处后,**不点回终端**,直接键盘敲: ```bash echo SHOULD_APPEAR ``` - 若回显:说明输入通道仍在 - 若不回显:说明焦点确实丢失,需要启用“保险带补丁” --- ## 3|常见故障 → 快速定位表 - **页面能开,但服务器下拉空**:优先回到 Step 2/3(路由未挂载或 API_BASE 未生效) - **连接按钮报 WS error**:先跑 `curl -i /ws/terminal/servers` 判 200/404,再看浏览器 Network → WS - **能连但不能输入**:先用 `echo` 判输入通道是否断,再考虑焦点补丁 - **输入重复**:检查是否每次 connect 都重复绑定 xterm 的 `onData`(应只绑定一次或重连前清理) --- ## 3.5|关键数据备忘(防遗忘) ### 3.5.1 本地端口与环境变量 - 后端(console-api):`http://127.0.0.1:5002` - 前端(Next dev):`http://localhost:3000` - 前端环境变量文件:`~/guanghu-dev/ghcs-mono/frontend/.env.local` - `NEXT_PUBLIC_CONSOLE_API=http://127.0.0.1:5002` - ⊢ 改 `.env.local` 后必须重启 `npm run dev` 才会生效 ### 3.5.2 登录与 Bearer token(API Keys 写操作必用) - 登录接口:`POST /api/login` - 返回字段:`access_token` + `token_type: bearer` - 本地默认管理员账号(见 `backend/auth.py`):`awen / guanghu2026` - 前端 token 存储位置(本次约定):`localStorage.ghcs_access_token` - 写请求必须带 header:`Authorization: Bearer ` ### 3.5.3 API Keys 关键接口(本次已验收) - `GET /api/keys/suppliers`(当前可不鉴权) - `GET /api/keys/list`(当前可不鉴权) - `POST /api/keys/add`(需鉴权) - `PUT /api/keys/{id}`(需鉴权;启停开关) - `DELETE /api/keys/{id}`(需鉴权) --- ## 4|推荐的“保险带补丁”(可选,但建议保留) 若遇到“点回黑框无法找回输入”,给终端容器外层加: ```tsx onMouseUp={() => term.current?.focus()} ``` 这能把“点黑框回焦”变成确定性行为。 --- ## 5|本次会话验收回执(可复制到执行记录) - `curl -i http://127.0.0.1:5002/ws/terminal/servers` → 200 - 终端回显:`whoami` / `pwd` / `echo FOCUS_OK` / `echo CLICK_FOCUS_OK` / `echo SHOULD_APPEAR` 全通过