multipart 图片文件名按真实内容类型给扩展名

- 新增 multipart_image_file_name,JPEG/WebP/GIF/AVIF 不再统一叫 .png
- 服务端仍按 MIME part 判定,文件名只作为未来消费者可依赖的事实保持一致
- 补扩展名映射单测
This commit is contained in:
2026-10-07 10:52:58 +08:00
parent 3ecd4efcbb
commit 3d6795978c
@@ -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!(