Skip to content

v0.24.1「压缩并下载」必然失败:archive.status 客户端载荷缺 sessionId(宿主 400);修复后 ready 轮询不停止还会双下载/误报 #798

Description

@nanami-0713

现象

v0.23.0(PR #782)引入的文件页「压缩并下载」在真实链路上必然失败:archive.build 成功后,轮询任务对 archive.status 的第一次调用(250ms 内)就被宿主以 400 拒绝:

missing or invalid "sessionId"

错误条随即显示 zipFailed,state === 'ready' 永远到不了,下载(save)不会发生——整条链只有 build 这一步是成功的。

根因:客户端载荷缺 sessionId,宿主要求两个参数

客户端 src/client/api.ts:470-472 只发 { id }:

export function archiveStatus(id: string): Promise<ArchiveBuildStatus> {
  return call<ArchiveBuildStatus>('archive.status', { id })
}

宿主 src/index.ts:601-602 两个参数都 requireString:

'archive.status': (payload) =>
  archiveTasks.status(requireString(payload, 'id'), requireString(payload, 'sessionId')),

requireString(src/wire.ts:95-102)对缺失键抛 bad-request。

对照同族两个入口,这里明显是漏带:

  • archive.build(api.ts:453)用 scopePayload(scope, …) 携带 sessionId;
  • archiveDownloadUrl(api.ts:477-479)的 GET 也带 sessionId(注释:the host answers only the session that built it)。

而 call() 本身是裸 fetch,不会自动附加 sessionId——文件头注释「Every call posts … with the sessionId」实际由各调用方负责放进去。

触发路径

文件树多选(或单目录)右键「压缩并下载」→ build 成功 → 轮询任务(src/client/FileTree.tsx:1378)await archiveStatus(job.id) → 400 → catch → failArchive(...)(FileTree.tsx:1393-1395)。100% 复现。

为什么测试全绿

  • tests/zip.spec.ts 的 status 用例全部直发 { id, sessionId }(如 :590)——测的是宿主侧,不是客户端实际载荷;
  • tests/file-tree-archive.spec.tsx:34 把 api.archiveStatus 整个 mock 掉了。

客户端实际发出的载荷形状没有任何测试覆盖。

修复方向

archiveStatus 改收 scope 并走 scopePayload(与 build / download URL 一致);宿主语义不变——sessionId 本来就是任务归属校验。顺带补一个「客户端真实载荷」形状的测试即可拦住回归。

顺带:本条修复后会显形的第二个问题(建议同批处理)

FileTree.tsx:1376-1397:轮询看到 state === 'ready' 后调 save(job.id, job.name)——saveArchive(:1340)是 void、不 await、也不先 settleArchive()(:1326),archiveJobId 保持非 null,250ms 轮询继续跑。而下载路由是消费式的:src/archive-route.ts:267 "A download consumes the task" + tasks.release,首次 GET 服务后任务即删。当首个 GET 往返超过一个轮询间隔(大包 / SSH 远端——正是本插件支持的形态)时:

  • 首个 GET 未完成 → 第二跳 status 仍 ready → 并发第二个 save(双下载,anchor.click 两次);
  • 首个 GET 已服务 → 第二跳 status 404 → failArchive('unknown or expired archive'),而 GET 成功回调又会 setActionError(null),两个回调落点顺序不定——常见终态是文件下载成功 + 错误条 zipFailed 并存。

本机小文件(<250ms)侥幸干净。建议:轮询看到 ready 后先 settleArchive() 停轮询(或在 save 前置重入护栏),再做恰好一次下载。


环境:v0.24.1(492661a)。v0.22.0 无此代码(整条 archive 链为 #782 新增)。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions