From 8a8c00fbb6a5065fdf817599cc856b54288eb9a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Wed, 23 Sep 2026 14:49:18 +0800 Subject: [PATCH] =?UTF-8?q?3D=20=E5=9B=BE=E7=94=9F=E8=BE=93=E5=85=A5?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E6=8A=8A=E3=80=8C=E7=BC=BA=E5=AF=B9=E8=B1=A1?= =?UTF-8?q?=E9=94=AE=E3=80=8D=E6=94=B9=E5=88=A4=E4=B8=BA=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E7=AB=AF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - resolve_source_object_key_with 在记录已解析但缺对象键时返回 502 与 model3d-image-source-object-key-missing,不再复用「引用不可用」的 400 - 未登记 / 跨 owner / 已删除仍收敛成同一句 400;缺对象键口径与 editor_project::validate_editor_reference_id_for_owner 的 BAD_GATEWAY 对齐 - 定向用例改名为 image_source_resolution_reports_missing_object_key_as_server_side_failure,断言状态码与 reason --- .../api-server/src/tripo3d/image_source.rs | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/server-rs/crates/api-server/src/tripo3d/image_source.rs b/server-rs/crates/api-server/src/tripo3d/image_source.rs index 20db2a31e..8b5b0be04 100644 --- a/server-rs/crates/api-server/src/tripo3d/image_source.rs +++ b/server-rs/crates/api-server/src/tripo3d/image_source.rs @@ -129,10 +129,12 @@ where if resolved.kind != requested_kind { return Err(image_source_kind_mismatch(requested_kind, resolved.kind)); } - resolved.object_key.ok_or_else(image_source_unavailable) + resolved + .object_key + .ok_or_else(image_source_object_key_missing) } -/// 未登记、跨 owner、已删除与缺少对象键都收敛成同一句 400。 +/// 未登记、跨 owner 与已删除都收敛成同一句 400。 fn image_source_unavailable() -> AppError { AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({ "provider": TRIPO_PROVIDER, @@ -142,6 +144,19 @@ fn image_source_unavailable() -> AppError { })) } +/// 记录已解析且归属调用方,但缺少对象键:这是 SpacetimeDB 行本身不完整,不是用户的引用不可用。 +/// +/// 归到 400 会让客户端照着「必须是已登记资源」去改一个改不动的地方,也丢掉「行存在但格式异常」 +/// 这个运维信号;口径与 `editor_project::validate_editor_reference_id_for_owner` 一致,按 5xx 上报。 +fn image_source_object_key_missing() -> AppError { + AppError::from_status(StatusCode::BAD_GATEWAY).with_details(json!({ + "provider": TRIPO_PROVIDER, + "reason": "model3d-image-source-object-key-missing", + "field": "source", + "message": "该图片引用已登记但缺少对象键,请稍后重试或联系支持。", + })) +} + /// `kind` 与 ID 实际指向的记录类型不一致;两者都由调用方给出,不涉及他人数据是否存在。 fn image_source_kind_mismatch(requested_kind: &str, resolved_kind: &str) -> AppError { AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({ @@ -217,9 +232,9 @@ mod tests { ); } - /// 记录存在但缺对象键与「引用不可用」收敛成同一句 400。 + /// 记录存在但缺对象键是服务端数据问题:报 5xx,不用「引用不可用」的 400 误导客户端。 #[tokio::test] - async fn image_source_resolution_treats_missing_object_key_as_unavailable() { + async fn image_source_resolution_reports_missing_object_key_as_server_side_failure() { let source = Model3dGenerationSource::Resource { resource_id: "res-1".to_string(), }; @@ -227,10 +242,13 @@ mod tests { let error = resolve_source_object_key_with(&source, |_| async { Ok(resolved("resource", None)) }) .await - .expect_err("缺对象键时必须按引用不可用处理"); + .expect_err("缺对象键时必须按服务端问题处理"); - assert_eq!(error.status_code(), StatusCode::BAD_REQUEST); - assert_eq!(reason_of(&error), Some("model3d-image-source-unavailable")); + assert_eq!(error.status_code(), StatusCode::BAD_GATEWAY); + assert_eq!( + reason_of(&error), + Some("model3d-image-source-object-key-missing") + ); } /// 未登记 / 跨 owner / 已删除这类 4xx 收敛成同一句 400;基础设施故障保留原状态码。