50 lines
3.3 KiB
Markdown
50 lines
3.3 KiB
Markdown
# 24 · 实例侧 401(launch token 过期)浏览器导航自动恢复
|
||||
|
|
|
|||
|
|
- 日期:2026-09-11
|
|||
|
|
- 触发:用户刷新实例子域页面(`admin.alotbuy.com`)看到 **`dsh web authentication required; reopen the URL printed by dsh web.`**,**既不自动跳转也不自动重启**
|
|||
|
|
- 结论一句话:**代理只处理了"门户侧 401"(会话失效),没处理"实例侧 401"(launch token 过期)** → 浏览器停在 dsh 的死端页。已修复:实例侧 401 + 浏览器导航 → 用当前实例的**最新 token 302 回同一地址**(拿不到则回门户)。
|
|||
|
|
- 状态:**已实施并上线**(服务已重启,`lib/` 已验证)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、现象与成因
|
|||
|
|
|
|||
|
|
| 环节 | 事实 |
|
|||
|
|
|---|---|
|
|||
|
|
| 触发场景 | 实例**重启后 token 轮换**(本次由我 00:14 为验证 picker 重启实例引起;此前 23:32 域名迁移 drain 亦同) |
|
|||
|
|
| 浏览器侧 | 旧标签页 URL 形如 `https://admin.alotbuy.com/?token=<旧token>`,token 已失效 |
|
|||
|
|
| dsh 侧 | 返回 `401` + 文案 `dsh web authentication required; reopen the URL printed by dsh web.`(HTML) |
|
|||
|
|
| 平台侧 | `proxy.ts` 的 401 处理**只覆盖门户自身判定**(`resolveSubdomainAccess` 的 `unauthorized` → 302 `/login.html`);**上游(实例)返回的 401 被原样透传** → 用户看到死端页 |
|
|||
|
|
| 为何没重启 | "自动重启"逻辑只在 `not_running`(404)分支触发;本例实例**正在运行**,只是 token 过期 |
|
|||
|
|
|
|||
|
|
## 二、修复(`src/supervisor/proxy.ts`)
|
|||
|
|
|
|||
|
|
1. `proxyHttp` 新增参数 `freshAuthUrl?: () => Promise<string | undefined>`;
|
|||
|
|
2. 上游响应为 **401 且是浏览器导航**(`GET` + `accept: text/html`)时:
|
|||
|
|
- `upRes.resume()` 释放上游连接;
|
|||
|
|
- 调用 `freshAuthUrl()` 取恢复地址并 **302**;
|
|||
|
|
3. 子域 hook 传入的 `freshAuthUrl`:`app.supervisor.status(userId).main?.launchToken` → 有 token 则 `https://<同一 Host>/?token=<新token>`(**原地恢复,无需重新登录**),否则回门户根;
|
|||
|
|
4. 路径式路由 `/u/:slug/dsh/` 同样接入(复用 `prefix`);
|
|||
|
|
5. `SubdomainAccess` 成功分支补充 `userId`(取 token 需要)。
|
|||
|
|
|
|||
|
|
## 三、验证
|
|||
|
|
|
|||
|
|
| 检查 | 结果 |
|
|||
|
|
|---|---|
|
|||
|
|
| `bash scripts/ci.sh`(typecheck + build + 单测) | ✅ 38 pass / 0 fail |
|
|||
|
|
| 运行产物 | ✅ `lib/supervisor/proxy.js` 含 `freshAuthUrl` ×3;`lib/supervisor/orchestrator.js` 含 `symlink` ×3(档案 23 的沙箱修复同时生效) |
|
|||
|
|
| 服务重启(drain) | ✅ `active` / 残留实例 0 / 门户 200 |
|
|||
|
|
| 端到端 | ⏳ 待用户实测:实例重启后刷新旧标签页应自动恢复(302 带新 token) |
|
|||
|
|
|
|||
|
|
## 四、回滚
|
|||
|
|
|
|||
|
|
- 代码:`/opt/dsh/backups/proxy.ts.bak-<TS>`;或 `git revert d7ab5b4` → `npm run build` → `systemctl restart dshs`。
|
|||
|
|
|
|||
|
|
## 五、顺带说明(本次一并上线)
|
|||
|
|
|
|||
|
|
- **档案 23 的沙箱修复同时生效**:实例 bwrap 参数补齐 `/bin`、`/sbin`、`/lib` 符号链接 → 实例内 **bash 工具恢复可用**(此前被 dsh 沙箱后端整体拒绝)。
|
|||
|
|
- 本次重启后所有实例已清空,用户下次进入会以新参数启动。
|
|||
|
|
|
|||
|
|
## 六、红线遵守
|
|||
|
|
|
|||
|
|
- 只改编排器自身代码(`src/supervisor/proxy.ts`),未触碰官方 dsh 主程序与缓存;修复走既有的"302 透明恢复"模式(与档案 13 的 not_running 自动重启同源)。
|