3.0 KiB
3.0 KiB
拼图生成图片读取链路修复
日期:2026-04-27
更新:2026-05-08
背景
拼图结果页的“生成或更换图片”会在 api-server 中调用 DashScope 生成图片,再把候选图上传到 OSS,最终以 /generated-puzzle-assets/... 旧兼容路径写回 PuzzleGeneratedImageCandidate.image_src 与草稿封面字段。
历史排查曾发现拼图图片写入路径已经进入 platform-oss::LegacyAssetPrefix::PuzzleAssets,但后端 Axum 旧资源代理和 Vite 本地代理没有挂载 /generated-puzzle-assets。当时的处理口径是补旧资源代理。
当前 WP-DEL 后,旧 /generated-* 直读代理已经物理删除;/generated-puzzle-assets/... 只允许作为 legacyPublicPath / OSS object key 标识。浏览器不能再直接请求该路径,必须通过 /api/assets/read-url?legacyPublicPath=... 换取短期签名 URL 后预览。
修复口径
platform-oss::LEGACY_PUBLIC_PREFIXES必须包含generated-puzzle-assets,保持直传票据、服务端上传、read-url 支持列表和错误提示同一口径。src/services/assetReadUrlService.ts的isGeneratedLegacyPath(...)需要同时识别/generated-puzzle-assets/...和generated-puzzle-assets/...。后者可能来自 object key 形态的历史字段。ResolvedAssetImage/useResolvedAssetReadUrl在签名 URL 返回前不能把裸/generated-*或generated-*写进<img src>。refreshKey只能用于跳过前端签名 URL 缓存并重新请求/api/assets/read-url,不能再给 OSS V4 签名 URL 追加_v等额外 query;OSS 会把 query 纳入签名,额外参数会让新生成图变成 403/破图。- 历史素材被选为参考图后,参考图小预览也必须走
ResolvedAssetImage,不能使用裸<img src="/generated-*">。 - 禁止恢复
/generated-puzzle-assets/{*path}Axum 路由或 Vite 直读代理;正式读取统一走/api/assets/read-url。
后续约束
- 任何新增
LegacyAssetPrefix都必须同时检查:platform-oss前缀枚举platform-oss::LEGACY_PUBLIC_PREFIXES/api/assets/read-url入参解析- 前端
isGeneratedLegacyPath(...)是否能识别
- 拼图候选图 JSON 仍保持 SpacetimeDB 持久化结构
PuzzleGeneratedImageCandidate的 snake_case 字段,不把 HTTP camelCase 响应结构写入draft_json。 - 图片生成、OSS 读写和外部参考图解析继续留在
api-server,不能下沉到 SpacetimeDB reducer。 - 如果图片组件需要刷新 generated 私有资源,优先让
refreshKey触发重新换签;不要修改已返回的signedUrl。
验收
npm run test -- src\services\assetReadUrlService.test.ts src\hooks\useResolvedAssetReadUrl.test.tsx src\components\puzzle-result\PuzzleResultView.test.tsxcargo test -p platform-oss --manifest-path server-rs\Cargo.tomlnpm run check:encodingnpm run api-server重启后检查/healthz,再点击拼图结果页“生成或更换图片”,候选图应能写回并正常展示。