Files
dsh_ai1net_server/dsh-server-docs/04-调整方案/24-实例侧401自动恢复.md
T
admin 5ad755116e chore(docs): 文档库并入代码仓(R4 选 a)+ 索引/台账跟进
1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
   保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
   工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
   必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
   + ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
   ⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
   验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
2026-09-15 18:47:13 +08:00

3.3 KiB
Raw Blame History

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 自动重启同源)。