Rust + Axum 文件上传与静态服务:用 multipart 流式落盘并托管前端
test12026-10-053 次阅读
需求拆解
一个典型的资源服务要做两件事:接收前端传来的文件,并把已上传的静态资源再吐回去。Axum 用 Multipart 提取器处理上传,用 tower_http 的 ServeDir 托管目录。关键是上传要"流式"写盘,别把大文件整块读进内存。
依赖
axum = "0.7"
tokio = { version = "1", features = ["full"] }
tower-http = { version = "0.5", features = ["fs"] }
流式上传 handler
Multipart 逐个字段遍历,每个字段用 chunk() 边读边写,避免 bytes() 一次性占内存。文件名必须过滤,否则用户可传 "../../etc/passwd" 造成路径穿越。
use axum::{
extract::Multipart,
http::StatusCode,
response::IntoResponse,
routing::post,
Router,
};
use tokio::io::AsyncWriteExt;
async fn upload(mut multipart: Multipart) -> Result<impl IntoResponse, StatusCode> {
while let Some(mut field) =
multipart.next_field().await.map_err(|_| StatusCode::BAD_REQUEST)?
{
let name = field.name().unwrap_or("file").to_string();
if name != "file" {
continue;
}
let fname = field.file_name().unwrap_or("upload.bin").to_string();
let path = format!("uploads/{}", sanitize(&fname));
let mut out = tokio::fs::File::create(&path)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
while let Some(chunk) =
field.chunk().await.map_err(|_| StatusCode::BAD_REQUEST)?
{
out.write_all(&chunk)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
}
out.flush().await.ok();
}
Ok(StatusCode::CREATED)
}
fn sanitize(name: &str) -> String {
name.chars()
.filter(|c| c.is_alphanumeric() || *c == '.' || *c == '_' || *c == '-')
.collect()
}
挂载路由与静态目录
nest_service 把 /static 路径交给 ServeDir,前端构建产物放进 public 目录后就能直接被访问。上传目录 uploads 与 public 分开,避免被静态服务直接列出。
use tower_http::services::ServeDir;
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/api/upload", post(upload))
.nest_service("/static", ServeDir::new("public"));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
.await
.unwrap();
axum::serve(listener, app).await.unwrap();
}
三个工程要点
- uploads 目录要提前创建(tokio::fs::create_dir_all),否则首个上传会 500。
- ServeDir 默认不列目录,若想禁止访问隐藏文件可加 .append_index_html_on_directories(false) 等配置。
- 生产环境应在反向代理(Nginx)层限制上传体大小,Axum 这边只做格式与落盘,别把限流逻辑压在应用里。
T
test1
文章作者
需求拆解 一个典型的资源服务要做两件事:接收前端传来的文件,并把已上传的静态资源再吐回去。Axum 用 Multipa...
- 分类
- 技术
- 发布时间
- 2026-10-05
- 字数
- 约 2236 字
- 阅读
- 3 次
