3D 预览产物 content type 改为按字节识别
- storage.rs 新增 sniff_preview_content_type(PNG / JPEG / WebP),resolve_artifact_content_type 改为按槽位判定:预览与模型一样先嗅探字节,嗅不出才回落声明值(最终仍回落 image/webp) - 修掉 provider / CDN 不写或写错 Content-Type 时 PNG 预览被写成 image/webp 并传播到 OSS metadata、asset_object.content_type 与生成结果的问题;对象键扩展名随之正确 - 定向用例重写为「字节优先 / 未知回落」两组,替换原先钉住「预览不嗅探」的用例 - 技术方案与决策记录同步该口径,并记录与其它图片链路(bgfilter / VectorEngine / 生成图落 OSS 适配器)的一致性对照
This commit is contained in:
@@ -9403,3 +9403,13 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- 影响面:`server-rs/crates/api-server/src/tripo3d/image_source.rs`(收敛分支、新增 `image_source_object_key_missing`、模块文档与定向用例)、[实施计划 Tripo生成Worker执行链路与API路由](../plans/【实施计划】Tripo生成Worker执行链路与API路由-2026-09-21.md)。
|
||||
- 验证方式:`cargo test --locked -p api-server tripo3d::image_source`(4 passed,含 `image_source_resolution_only_collapses_unavailable_references` 覆盖 400 / 404 收敛与 403 / 409 / 500 保留、`image_source_resolution_reports_missing_object_key_as_server_side_failure` 断言 502 与 reason)、`rustfmt --check`。
|
||||
- 关联文档:[技术方案 Tripo 3D生成API集成](../../technical/【技术方案】Tripo 3D生成API集成-2026-09-21.md)、[实施计划 Tripo生成Worker执行链路与API路由](../plans/【实施计划】Tripo生成Worker执行链路与API路由-2026-09-21.md)。
|
||||
|
||||
## 2026-09-23 3D 预览产物 content type 改为按字节识别:只信 provider 声明的做法作废
|
||||
|
||||
- 背景:`tripo3d/storage.rs` 的 `Preview` 槽位原先不做字节嗅探,`application/octet-stream` 或空 `Content-Type` 一律写成 `image/webp` + `.webp` 文件名;而 `worker.rs` 的 `preview_dimensions` 早已用 `ImageReader::with_guessed_format()` 解出过真实格式(PNG / JPEG)却没往下传。Tripo 的渲染图 CDN 不写或写错 `Content-Type` 时,PNG 预览就会带着 `image/webp` 进 OSS metadata、`asset_object.content_type` 与生成结果的 `Model3dGeneratedArtifact.content_type`。
|
||||
- 决策:预览槽位与模型槽位同处一个判定点,按字节魔数识别 PNG / JPEG / WebP 后再决定 content type;识别范围外(含模型字节、非图片字节)保持既有回落(声明值可用就用声明值,否则 `image/webp`)。模型槽位行为不变。
|
||||
- 原因:**浏览器能容忍,不代表记录值可以继续说谎**。`<img>` 会按魔数嗅探,所以前端预览一直没坏;但 `assets.rs` 的 `"contentType"` 出参、素材库下载命名、后台与将来的服务端处理都信任 `asset_object.content_type`,对象键扩展名也由它派生。仓库同类图片链路的现行口径都是「字节是真相」——bgfilter 用 `guess_format` 定 mime 并把声明头只当一致性校验、VectorEngine 生成图走 `infer_image_mime_type`、生成图落 OSS 适配器的后缀与 PUT `content_type` 都取自嗅探结果;只有嗅不动的视频(`character_animation_assets.rs`)与回读已存对象的 HEAD 才信 header。本次把预览槽位对齐到这条口径,而不是删字段:删字段只会把 `image/webp` 换成同样错的 `application/octet-stream`,还要付 `Model3dGeneratedArtifact.content_type` 的破坏性契约变更代价。
|
||||
- 代价与取舍:多一次只读文件头的嗅探(不解码像素);worker 的 `preview_dimensions` 与 storage 的嗅探仍是两处调用,但前者是「必须能解码」的正交校验、后者是写库前的类型归一,判定点只有一个(`resolve_artifact_content_type`)。嗅探不到的格式不猜,仍回落 `image/webp`,因此不会因为一张少见格式的渲染图而失败退款。
|
||||
- 影响面:`server-rs/crates/api-server/src/tripo3d/storage.rs`(新增 `sniff_preview_content_type`、`resolve_artifact_content_type` 改为按槽位判定、定向用例重写为「字节优先 / 未知回落」两组)、[技术方案 Tripo 3D生成API集成](../../technical/【技术方案】Tripo 3D生成API集成-2026-09-21.md)。
|
||||
- 验证方式:`cargo test --locked -p api-server tripo3d::`(56 passed,含 `preview_content_type_follows_bytes_over_declaration` 与 `preview_content_type_keeps_declaration_when_bytes_are_unknown`)、`rustfmt --check`、`npm run check:encoding`、`node scripts/check-doc-index.mjs`。
|
||||
- 关联文档:[技术方案 Tripo 3D生成API集成](../../technical/【技术方案】Tripo 3D生成API集成-2026-09-21.md)、[实施计划 Tripo生成API契约与数据模型](../plans/【实施计划】Tripo生成API契约与数据模型-2026-09-21.md)。
|
||||
|
||||
Reference in New Issue
Block a user