From 3d6795978cc01304abac3d1e4722de4dd4c8fc0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Wed, 7 Oct 2026 10:52:58 +0800 Subject: [PATCH] =?UTF-8?q?multipart=20=E5=9B=BE=E7=89=87=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=90=8D=E6=8C=89=E7=9C=9F=E5=AE=9E=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E7=BB=99=E6=89=A9=E5=B1=95=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 multipart_image_file_name,JPEG/WebP/GIF/AVIF 不再统一叫 .png - 服务端仍按 MIME part 判定,文件名只作为未来消费者可依赖的事实保持一致 - 补扩展名映射单测 --- .../src/game_distribution_publish.rs | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs b/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs index 207efb87d..b581a3ffd 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs @@ -1162,17 +1162,37 @@ fn publish_multipart_form( .map_err(|error| format!("构建发布资料 part 失败:{error}"))?, ); if let Some(cover) = media.cover.as_ref() { - form = form.part("cover", multipart_image_part(cover, "cover.png")?); + form = form.part( + "cover", + multipart_image_part( + cover, + &multipart_image_file_name("cover", cover.content_type), + )?, + ); } for (index, screenshot) in media.screenshots.iter().enumerate() { form = form.part( "screenshot", - multipart_image_part(screenshot, &format!("screenshot-{index}.png"))?, + multipart_image_part( + screenshot, + &multipart_image_file_name(&format!("screenshot-{index}"), screenshot.content_type), + )?, ); } Ok(form) } +/// multipart 文件名按真实内容类型给扩展名:JPEG/WebP 等不再一律叫 `.png`。 +/// +/// 服务端按 MIME part 判定,文件名只是给未来消费者看的事实;这里保持与 `content_type` 一致。 +fn multipart_image_file_name(part_name: &str, content_type: &str) -> String { + let extension = match content_type { + "image/jpeg" => "jpg", + other => other.strip_prefix("image/").unwrap_or("bin"), + }; + format!("{part_name}.{extension}") +} + fn multipart_image_part( image: &DraftImage, file_name: &str, @@ -1852,6 +1872,23 @@ mod tests { assert!(image_content_type("cover").is_err()); } + #[test] + fn multipart_image_file_name_follows_content_type() { + assert_eq!(multipart_image_file_name("cover", "image/png"), "cover.png"); + assert_eq!( + multipart_image_file_name("cover", "image/jpeg"), + "cover.jpg" + ); + assert_eq!( + multipart_image_file_name("screenshot-2", "image/webp"), + "screenshot-2.webp" + ); + assert_eq!( + multipart_image_file_name("screenshot-0", "application/octet-stream"), + "screenshot-0.bin" + ); + } + fn fixture_root(prefix: &str) -> std::path::PathBuf { static NEXT_TEST_ID: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0); let root = std::env::temp_dir().join(format!(