Skip to content

objectui: shadcn-sync 的 registry 缓存会把 403/HTML 错误响应当成正常数据缓存 1 小时,一次网络抖动毒化后续所有 --check #5803

Description

@yinlianghui

发现于 objectstack#5505 / objectui PR #3455 的实施过程,与该 PR 无关,单独记录。

现象

scripts/shadcn-sync.jsfetchUrl 不检查 HTTP 状态码:

https.get(url,(res)=>{letdata='';res.on('data',(chunk)=>{data+=chunk;});res.on('end',()=>{try{resolve(JSON.parse(data));}catch(e){resolve(data);}});})

非 JSON 的响应体(403 页面、代理错误页、502 HTML)会走 catch 分支被当作成功结果原样 resolve。紧接着 fetchRegistry 无条件把它写进磁盘缓存:

constdata=awaitfetchUrl(url);cacheStats.misses++;try{awaitfs.mkdir(CACHE_DIR,{recursive: true});awaitfs.writeFile(cacheFileFor(url),JSON.stringify({ url,fetchedAt: Date.now(), data }));}

缓存 TTL 是 1 小时(CACHE_TTL_MS),所以一次瞬时失败会让之后一小时内的 pnpm shadcn:check不再重试,持续基于垃圾数据报告。

实测证据

在 egress 拦截 ui.shadcn.com 的环境里连跑两次 pnpm shadcn:check:

  • 第一次:46 个组件全部 fetch 到 Host not in allowlist: ui.shadcn.com... 文本
  • 第二次汇总行:Registry: 46 cached, 0 fetched (cache TTL 60min — --no-cache to force live)

即错误响应被完整缓存并在第二次运行中被当作有效数据取用,一次真实请求都没发。

影响

网络恢复后,开发者本地的 --check 在一小时内仍报 46 个 error,且看不出原因是缓存(汇总行说的是 "cached",容易被读成"已是最新")。--update 不读缓存(注释里明确写了写操作不走缓存),因此不会写出坏文件 —— 影响面限于 --check / --diff 的可信度与本地 DX。

建议方向

  1. fetchUrl 检查 res.statusCode,非 2xx 直接 reject;
  2. fetchRegistry 仅在拿到可解析且形状正确(有 files[0].content)的响应时才写缓存。

两者独立,任一条都能挡住这个场景;第 2 条同时能挡住 registry schema 变更的情况。

备注

objectui PR #3455 已在 --check 侧就地加了防御:registry 返回不可用内容时按 fetch error 处理,不会让它流进比较逻辑、也不会误报"补丁失效"。但那只是让新增的闸门免疫,缓存毒化本身仍在。

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions