修复生成图片签名地址重复换签

将 refreshKey 调整为 signed URL 缓存版本号,同一路径同版本复用未过期签名地址。

让完整阿里云 OSS generated 地址在 hook 中先归一并走 read-url 换签。

补充前端回归测试,覆盖相同 refreshKey 不重复换签和完整 OSS 地址不裸写入图片。

更新运维文档与 Hermes 记忆,明确 refreshKey 不是每次绕过签名缓存。
This commit is contained in:
2026-06-07 23:20:24 +08:00
parent d3a3238028
commit 2a6da01307
7 changed files with 136 additions and 16 deletions

View File

@@ -19,8 +19,8 @@
- 现象:同一张 OSS generated 图片每次展示都重新从 OSS 拉取,或者完整 OSS 私有 URL 裸请求返回 403。
- 原因:前端输入如果是 `https://*.oss-*.aliyuncs.com/generated-*`,会被当普通绝对 URL 直连,绕过 `/api/assets/read-url` 和 signed URL 本地缓存;旧 OSS 对象如果缺少 `Cache-Control`,浏览器只能依赖 `ETag` / `Last-Modified` 做 304 协商缓存,不会长期强缓存。
- 处理:完整 OSS generated URL 先归一成 `/generated-*` legacy public path再走 `/api/assets/read-url` 换签;新上传 generated 私有对象由 `platform-oss``PostObject` form fields / policy 和服务端 `PutObject` 请求头中写入 `Cache-Control: public, max-age=31536000, immutable`。不要把 api-server 变成图片静态代理,也不要把 OSS 内容 fallback 到服务器磁盘。
- 验证:前端测试应看到完整 OSS generated URL 调用 `/api/assets/read-url?legacyPublicPath=...``cargo test -p platform-oss --manifest-path server-rs/Cargo.toml` 应覆盖 `Cache-Control` policy、form field、PutObject headers 和 V4 `AdditionalHeaders`;线上旧对象可用 `curl -I` 观察是否只有 `ETag` / `Last-Modified` 或已经补齐 `Cache-Control`
- 处理:完整 OSS generated URL 先归一成 `/generated-*` legacy public path再走 `/api/assets/read-url` 换签;`refreshKey` 是 signed URL 缓存版本号,同一路径、同一版本且未临近过期时必须复用,不要每次渲染都强制重新换签。新上传 generated 私有对象由 `platform-oss``PostObject` form fields / policy 和服务端 `PutObject` 请求头中写入 `Cache-Control: public, max-age=31536000, immutable`。不要把 api-server 变成图片静态代理,也不要把 OSS 内容 fallback 到服务器磁盘。
- 验证:前端测试应看到完整 OSS generated URL 调用 `/api/assets/read-url?legacyPublicPath=...`,且相同 `refreshKey` 不重复换签`cargo test -p platform-oss --manifest-path server-rs/Cargo.toml` 应覆盖 `Cache-Control` policy、form field、PutObject headers 和 V4 `AdditionalHeaders`;线上旧对象可用 `curl -I` 观察是否只有 `ETag` / `Last-Modified` 或已经补齐 `Cache-Control`
- 关联:`src/services/assetReadUrlService.ts``server-rs/crates/platform-oss/src/lib.rs``server-rs/crates/platform-oss/README.md``docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`
## 小程序 H5 导航不能清掉宿主 query
@@ -1032,8 +1032,8 @@
## 拼图生成完成后图片只显示破图或 alt 文案
- 现象:拼图结果页生成完成后,“画面图”区域出现破图图标和作品名,图片无法正常预览;但打开历史拼图素材时同一张图可能可以正常预览。
- 原因:拼图正式图保存为 `/generated-puzzle-assets/*` 兼容标识,旧 `/generated-*` 直读代理已删除;如果前端没有通过 `ResolvedAssetImage` / `/api/assets/read-url` 换签,或收到无前导斜杠的 `generated-puzzle-assets/*` object key 后未识别为 generated 私有资源,浏览器会直接请求裸路径并失败。生成完成后的结果图还会传入 `refreshKey`,它只能用于重新请求 `/api/assets/read-url`,不能给 OSS V4 签名 URL 追加 `_v`OSS 会把 query 纳入签名,额外参数会让签名失效,历史素材常因未传 `refreshKey` 而表现正常
- 处理:拼图结果页、发布预览、运行态和历史素材预览都走 `ResolvedAssetImage``useResolvedAssetReadUrl``isGeneratedLegacyPath(...)` 必须同时识别 `/generated-*``generated-*``refreshKey` 只绕过前端签名缓存并重新换签,不修改已返回的 OSS 签名 URL禁止恢复 `/generated-puzzle-assets` 直读代理。
- 原因:拼图正式图保存为 `/generated-puzzle-assets/*` 兼容标识,旧 `/generated-*` 直读代理已删除;如果前端没有通过 `ResolvedAssetImage` / `/api/assets/read-url` 换签,或收到无前导斜杠的 `generated-puzzle-assets/*` object key 后未识别为 generated 私有资源,浏览器会直接请求裸路径并失败。生成完成后的结果图还会传入 `refreshKey`,它只能作为 signed URL 缓存版本号,不能给 OSS V4 签名 URL 追加 `_v`OSS 会把 query 纳入签名,额外参数会让签名失效。
- 处理:拼图结果页、发布预览、运行态和历史素材预览都走 `ResolvedAssetImage``useResolvedAssetReadUrl`generated 私有资源识别必须同时覆盖 `/generated-*``generated-*``https://*.oss-*.aliyuncs.com/generated-*``refreshKey` 变化时重新换签,同一路径同一 `refreshKey` 且签名未临近过期时复用已返回的 OSS 签名 URL禁止恢复 `/generated-puzzle-assets` 直读代理。
- 验证:运行 `npm run test -- src\services\assetReadUrlService.test.ts src\hooks\useResolvedAssetReadUrl.test.tsx src\components\puzzle-result\PuzzleResultView.test.tsx`,再触发一次真实生成确认 Network 中先请求 `/api/assets/read-url`,图片 `src` 为未追加 `_v` 的签名 URL。
- 关联:`src/services/assetReadUrlService.ts``src/components/ResolvedAssetImage.tsx``docs/technical/PUZZLE_IMAGE_ASSET_PROXY_FIX_2026-04-27.md`