diff --git a/server-rs/crates/api-server/src/tripo3d/routes.rs b/server-rs/crates/api-server/src/tripo3d/routes.rs index be6f6f83e..9d7eac162 100644 --- a/server-rs/crates/api-server/src/tripo3d/routes.rs +++ b/server-rs/crates/api-server/src/tripo3d/routes.rs @@ -58,7 +58,7 @@ pub(crate) async fn submit_text_to_model( payload: Result, JsonRejection>, ) -> Result<(StatusCode, Json), Response> { let payload = parse_json_payload(&request_context, payload)?; - let idempotency_key = require_idempotency_key(&headers)?; + let idempotency_key = require_idempotency_key(&headers, &request_context)?; let query = validate_text_to_model_request(&payload) .map_err(map_request_error) .map_err(|error| error.into_response_with_context(Some(&request_context)))?; @@ -86,7 +86,7 @@ pub(crate) async fn submit_image_to_model( payload: Result, JsonRejection>, ) -> Result<(StatusCode, Json), Response> { let payload = parse_json_payload(&request_context, payload)?; - let idempotency_key = require_idempotency_key(&headers)?; + let idempotency_key = require_idempotency_key(&headers, &request_context)?; let query = validate_image_to_model_request(&payload) .map_err(map_request_error) .map_err(|error| error.into_response_with_context(Some(&request_context)))?; @@ -172,7 +172,10 @@ fn target_source_entity_id( } /// 两个提交都必须显式给出 `Idempotency-Key`;缺失或格式非法一律 400,不静默生成键。 -fn require_idempotency_key(headers: &HeaderMap) -> Result<&str, Response> { +fn require_idempotency_key<'a>( + headers: &'a HeaderMap, + request_context: &RequestContext, +) -> Result<&'a str, Response> { let value = headers .get("idempotency-key") .and_then(|value| value.to_str().ok()) @@ -184,7 +187,7 @@ fn require_idempotency_key(headers: &HeaderMap) -> Result<&str, Response> { "provider": super::provider::TRIPO_PROVIDER, "message": "3D 生成提交必须携带 Idempotency-Key 请求头。", })) - .into_response_with_context(None) + .into_response_with_context(Some(request_context)) })?; if value.len() > 128 || !value.bytes().all(|byte| (0x21..=0x7e).contains(&byte)) { return Err(AppError::from_status(StatusCode::BAD_REQUEST) @@ -192,7 +195,7 @@ fn require_idempotency_key(headers: &HeaderMap) -> Result<&str, Response> { "provider": super::provider::TRIPO_PROVIDER, "message": "Idempotency-Key 必须是 1-128 个可打印 ASCII 字符,且不能包含空格。", })) - .into_response_with_context(None)); + .into_response_with_context(Some(request_context))); } Ok(value) } @@ -215,23 +218,29 @@ mod tests { #[test] fn idempotency_key_is_required_and_validated() { + let request_context = RequestContext::new( + "request-idempotency-key".to_string(), + "test".to_string(), + std::time::Duration::ZERO, + false, + ); let missing = HeaderMap::new(); - assert!(require_idempotency_key(&missing).is_err()); + assert!(require_idempotency_key(&missing, &request_context).is_err()); let mut headers = HeaderMap::new(); headers.insert("idempotency-key", HeaderValue::from_static("issue-1")); assert_eq!( - require_idempotency_key(&headers).expect("合法键应通过"), + require_idempotency_key(&headers, &request_context).expect("合法键应通过"), "issue-1" ); let mut blank = HeaderMap::new(); blank.insert("idempotency-key", HeaderValue::from_static(" ")); - assert!(require_idempotency_key(&blank).is_err()); + assert!(require_idempotency_key(&blank, &request_context).is_err()); let mut spaced = HeaderMap::new(); spaced.insert("idempotency-key", HeaderValue::from_static("a b")); - assert!(require_idempotency_key(&spaced).is_err()); + assert!(require_idempotency_key(&spaced, &request_context).is_err()); } /// 两个路由必须真的挂在应用路由上并走统一鉴权:路径写错或漏 merge 会退化成 404。