From 1be77d2f99ee78f828a1c2879dc4ed72006d24b5 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:51:09 +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=E5=8F=AA=E6=94=B6=E6=95=9B=E3=80=8C=E5=BC=95?= =?UTF-8?q?=E7=94=A8=E4=B8=8D=E5=8F=AF=E7=94=A8=E3=80=8D=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - resolve_source_object_key_with 的 4xx 收敛从 is_client_error() 收窄为 400 / 404,不再把 403 服务身份校验失败与 409 并发冲突也说成「图片必须是已登记资源」 - 与模块注释「只有基础设施失败保留原状态码」的实际口径统一,403 / 409 / 5xx 一律按原状态码上报 - 定向用例改名 image_source_resolution_only_collapses_unavailable_references,覆盖 400 / 404 收敛与 403 / 409 / 500 保留 --- .../api-server/src/tripo3d/image_source.rs | 60 +++++++++++-------- 1 file changed, 35 insertions(+), 25 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 8b5b0be04..4bc6665cc 100644 --- a/server-rs/crates/api-server/src/tripo3d/image_source.rs +++ b/server-rs/crates/api-server/src/tripo3d/image_source.rs @@ -118,12 +118,12 @@ where Model3dGenerationSource::Asset { asset_id } => ("asset", asset_id.as_str()), }; let resolved = resolve(reference_id.to_string()).await.map_err(|error| { - // 未登记、跨 owner 与已删除在 provider 侧都是同一类“引用不可用”, - // 这里也收敛成同一句 400;只有基础设施故障才继续按原状态码上报。 - if error.status_code().is_client_error() { - image_source_unavailable() - } else { - error + // 只有「未登记(404)/ 引用非法(400)」这一类才是“引用不可用”,收敛成同一句 400; + // 403(服务身份校验失败)、409(版本冲突)与 5xx 都是基础设施 / 并发失败, + // 把它们也说成「图片必须是已登记资源」会指错方向,因此继续按原状态码上报。 + match error.status_code() { + StatusCode::BAD_REQUEST | StatusCode::NOT_FOUND => image_source_unavailable(), + _ => error, } })?; if resolved.kind != requested_kind { @@ -251,31 +251,41 @@ mod tests { ); } - /// 未登记 / 跨 owner / 已删除这类 4xx 收敛成同一句 400;基础设施故障保留原状态码。 + /// 未登记(404)与引用非法(400)收敛成同一句 400;403 / 409 与 5xx 一律保留原状态码。 #[tokio::test] - async fn image_source_resolution_collapses_client_errors_but_keeps_infra_errors() { + async fn image_source_resolution_only_collapses_unavailable_references() { let source = Model3dGenerationSource::Resource { resource_id: "res-1".to_string(), }; - let collapsed = resolve_source_object_key_with(&source, |_| async { - Err(probe_error(StatusCode::NOT_FOUND)) - }) - .await - .expect_err("4xx 必须收敛"); - assert_eq!(collapsed.status_code(), StatusCode::BAD_REQUEST); - assert_eq!( - reason_of(&collapsed), - Some("model3d-image-source-unavailable") - ); + for unavailable in [StatusCode::BAD_REQUEST, StatusCode::NOT_FOUND] { + let collapsed = resolve_source_object_key_with(&source, |_| async move { + Err(probe_error(unavailable)) + }) + .await + .expect_err("引用不可用必须收敛"); + assert_eq!(collapsed.status_code(), StatusCode::BAD_REQUEST); + assert_eq!( + reason_of(&collapsed), + Some("model3d-image-source-unavailable") + ); + } - let kept = resolve_source_object_key_with(&source, |_| async { - Err(probe_error(StatusCode::INTERNAL_SERVER_ERROR)) - }) - .await - .expect_err("基础设施故障必须继续报错"); - assert_eq!(kept.status_code(), StatusCode::INTERNAL_SERVER_ERROR); - assert_eq!(reason_of(&kept), Some("probe")); + // 403 来自 spacetime runtime 的服务身份校验、409 来自并发写入:都不是用户的引用写错了, + // 收敛成 400 会把基础设施故障说成「图片必须是已登记资源」。 + for kept_status in [ + StatusCode::FORBIDDEN, + StatusCode::CONFLICT, + StatusCode::INTERNAL_SERVER_ERROR, + ] { + let kept = resolve_source_object_key_with(&source, |_| async move { + Err(probe_error(kept_status)) + }) + .await + .expect_err("基础设施 / 并发故障必须继续报错"); + assert_eq!(kept.status_code(), kept_status); + assert_eq!(reason_of(&kept), Some("probe")); + } } /// 本模块只做定点解析:一旦退回「列工程 / 列素材库再筛」的老路,