perf(upload): offload GIF/WebP raw image validation to spawn_blocking

GIF 走 image::load_from_memory 会完整解码动画帧,在 async 上下文阻塞
worker。移到 spawn_blocking,JoinError 兜底任务失败。
This commit is contained in:
xfy 2026-06-18 11:19:34 +08:00
parent 033b89ccb8
commit 753525fb41

View File

@ -205,15 +205,33 @@ pub async fn upload_image(
let is_gif = mime_type.as_str() == "image/gif"; let is_gif = mime_type.as_str() == "image/gif";
let is_webp = mime_type.as_str() == "image/webp"; let is_webp = mime_type.as_str() == "image/webp";
// 对不经过重编码的格式做解码验证。 // 对不经过重编码的格式做解码验证。GIF 走 image::load_from_memory 会完整解码,
if (is_gif || is_webp) && !validate_raw_image(&data, mime_type.as_str()) { // 移到阻塞线程池避免拖住 async 运行时。
return Err(( if is_gif || is_webp {
StatusCode::BAD_REQUEST, let validate_data = data.to_vec();
Json(json!({ let validate_mime = mime_type.clone();
"success": false, let is_valid = tokio::task::spawn_blocking(move || {
"error": "图片文件损坏或格式不正确" validate_raw_image(&validate_data, validate_mime.as_str())
})), })
)); .await
.map_err(|_| {
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({
"success": false,
"error": "图片校验任务失败"
})),
)
})?;
if !is_valid {
return Err((
StatusCode::BAD_REQUEST,
Json(json!({
"success": false,
"error": "图片文件损坏或格式不正确"
})),
));
}
} }
// GIF 与 WebP 保持原格式;其余格式尝试转 WebP。 // GIF 与 WebP 保持原格式;其余格式尝试转 WebP。