Commit Graph
4 Commits
Author SHA1 Message Date
admin ed0c3c0ad5 fix(proxy): 治本 —— 陈旧 dsh-auth cookie 回写清理(档案 98,修 431 → Failed to load plugins)
根因(2026-09-14 实测):dsh **每次实例 (重)启动都换** `dsh-auth-<随机后缀>` 的 **cookie 名**;平台此前
只在**转发给实例时**丢弃旧的(`mergeCookieHeader`),**从不回写浏览器** ⇒ 浏览器 cookie jar **只增不减**
⇒ `Cookie` 请求头越涨越长 ⇒ 实测 **12.8 KB 放行 / 19.1 KB 就被 431**(且 19 KB 时连 `/` 也 431)
⇒ 被 Cloudflare / 本机 nginx 直接拒掉,**请求根本到不了平台** ⇒ 那条 11 MB 合并脚本取不到
⇒ 客户端报 `bundle script … failed to load` ⇒ 界面「Failed to load plugins」。
(旁证全对:平台日志无该请求 ✓/无痕正常=空 cookie 罐 ✓/服务器侧一切正常 ✓)

修法(只动 proxy.ts 一处):在响应头块里对**陈旧名字**回写 `Set-Cookie: <name>=; Path=/; Max-Age=0`。
· **只在「本次响应确实下发了 dsh-auth-*」时才动手** —— 那时才确知当前有效名字,绝不误删在用的那个;
· 其余情形什么都不做;不带 `Domain=`(dsh 下发的是 host-only cookie);
· 即使判断有误,档案 51 的「401 → 取新 cookie 透明重放」也会自愈。

验证:
· 本机 `npm run verify` EXIT=0;服务器 `ci.sh` CI OK(48 pass / 0 fail);
· `scripts/verify-inject.cjs` 新增防回退断言「会清理陈旧 dsh-auth cookie」;
· **端到端实测**:带 2 个假 `dsh-auth-*` 请求 `/?token=…` → 303 响应含 **3 条 Set-Cookie,其中 2 条 Max-Age=0**
  正是那两个假名字 ✅

⚠️ 它**救不了已经 431 的当下**(那时请求在 CF/nginx 就被拒、到不了平台)⇒ 用户需**先手动清一次**
(只删 `dsh-auth-*`、保留 `sid`),此后由本机制维持小 jar。⚠️ 根因仍在(官方每重启换名)⇒ **少重启**仍是要点。
2026-09-14 23:01:04 +08:00
admin cc1dc5c9a8 fix(proxy): /plugins/ 合并脚本补 ETag + 304 短路 —— 省掉每次 11 MB 重下(档案 97)
问题(实测 2026-09-14):官方 `@deepseek-ai/dsh-client-modules` 把全部客户端插件拼成**一条
11,172,365 字节的脚本**(combo URL `/plugins/??<模块列表>&rev=<revision>`);我们给它下发
`no-cache`(档案 95,为"改了 UI 就能看到"),而实例**既不给 ETag 也不给 Last-Modified**
⇒ 浏览器"回源校验"退化成**每次全量重下 11 MB** —— 经 Cloudflare 实测 **114.87 秒**
(弱网/手机上直接表现为页面加载不出来)。

修法(只动 proxy.ts 一处,不改官方、不动 rev):
· 按 URL 派生强校验器 `ETag = sha1(targetPath)`,**只对 GET/HEAD + /plugins/ 且 URL 含 `rev=` 生效**
  (无 rev 一律跳过)。依据是官方契约:「**已公告响应不可变;未知组合或 revision 返回 404**」
  ⇒ (模块组合, rev) 唯一决定内容 ⇒ 同 URL 必同字节,故按 URL 派生 ETag 是安全的。
· 命中 `If-None-Match` 时 **直接回 304、完全不回源**(省的正是那 11 MB)。
· 未命中时行为与原先一致,只在既有缓存头区块多透出一个 `ETag`。

验证:
· 本机 `npm run verify` EXIT=0;服务器 `ci.sh` CI OK(48 pass / 0 fail);
· `scripts/verify-inject.cjs` 新增防回退断言「proxy.ts 有 /plugins/ ETag + 304 短路」;
· **端到端实测**:① 首次 200 / 11,172,365 B + `ETag="034a459a92…"`;② 带 If-None-Match → **304 / 0 B** ✅

⚠️ 顺带记录:本仓库 `core.autocrlf` 会在 git 触碰后把工作区文件改成 CRLF ⇒ 脚本化改文件必须
**行尾自适应**(本轮 `proxy.ts` 的多行匹配因此失配过一次)。
2026-09-14 22:46:40 +08:00
admin e18eaa2b64 fix(proxy): HTML 外壳也下发 no-cache —— 修「Failed to load plugins」根因(档案 95)
症状:用户页面报
  client-modules: bundle script /plugins/??…&rev=… failed to load  ⇒ 界面「Failed to load plugins」

根因(实测三条对照):
· `GET /`(外壳 HTML)**没有任何缓存头**(无 Cache-Control/ETag/Last-Modified/Expires)⇒ 浏览器启发式缓存
· 外壳内嵌带**内容哈希 `rev`** 的插件 bundle URL;`rev`/模块列表与实例当前状态**必须完全一致**:
  原样 200(11.17 MB)|只改 rev → **404**|rev 对但少一个模块 → **404**
· 于是「改了插件 / 重启了实例」之后,旧外壳永远去请求**已不存在的 rev** ⇒ 404 ⇒ 报错,
  且**普通刷新会命中缓存的外壳 ⇒ 复现不消失**(2026-09-14 事故:当天连铺 4 次插件 + 3 次重启 dshs)

修法:把既有的 `no-cache` 治理(2026-09-12 只覆盖 `/plugins/`、`/assets/`)**扩到 HTML 外壳**——
`String(headers['content-type']).includes('text/html')` 也下发 `Cache-Control: no-cache`。
实例端仍是唯一事实源,平台只加缓存头,不改 rev(R2)。

验证:
· 服务器 `bash scripts/ci.sh` → CI OK(48 pass / 0 fail)
· `scripts/verify-inject.cjs` 新增防回退断言「/plugins/ 与 text/html 都必须 no-cache」
· 经 nginx 公网路径实测 `GET /` → **cache-control: no-cache**(改前为空)
· 端到端:取各用户页面里**自身**的 bundle URL 回拉 → admin/guest 均 200(11.69 / 11.13 MB)

⚠️ 本提交不能回溯治愈「已经坏在用户浏览器里的那份旧外壳」——用户需**强刷一次**
(Ctrl/Cmd+Shift+R,或 DevTools 勾 Disable cache,或无痕窗口)。

⚠️ 同批未提交(属别人 lane,见档案 95 §六):`BRIEF.md` / `DEPLOY-本部署.md` 的配额口径同步
(我改了它们的配额数字,但那两个文件本就有别人未提交的改动 ⇒ 不跟提,宁可保持 dirty)。
2026-09-14 21:50:28 +08:00
admin 43976fea6a 初始提交:DSH 多租户平台(dshs) 2026-09-13 16:18:10 +08:00