Axum Multipart Upload Size Limits
Accept multipart uploads in Axum with per-field size caps, MIME allowlists, and streaming field reads that cap total request bytes.
Code
use axum::{
extract::{DefaultBodyLimit, Multipart},
http::StatusCode,
routing::post,
Router,
};
use futures_util::StreamExt;
use std::path::PathBuf;
const MAX_BODY: usize = 20 * 1024 * 1024;
const MAX_FIELD: usize = 15 * 1024 * 1024;
const ALLOWED_MIME: [&str; 2] = ["image/png", "application/pdf"];
async fn upload(mut multipart: Multipart) -> Result<(StatusCode, String), StatusCode> {
let mut saved = Vec::new();
while let Some(field) = multipart
.next_field()
.await
.map_err(|_| StatusCode::BAD_REQUEST)?
{
let name = field.name().unwrap_or("file").to_string();
let mime = field.content_type().unwrap_or("").to_string();
if !ALLOWED_MIME.contains(&mime.as_str()) {
return Err(StatusCode::UNSUPPORTED_MEDIA_TYPE);
}
let mut written: usize = 0;
let mut buffer: Vec<u8> = Vec::with_capacity(8 * 1024);
// 分块读取字段流:单字段上限即时检查
while let Some(chunk) = field
.chunk()
.await
.map_err(|_| StatusCode::BAD_REQUEST)?
{
written += chunk.len();
if written > MAX_FIELD {
return Err(StatusCode::PAYLOAD_TOO_LARGE);
}
buffer.extend_from_slice(&chunk);
}
let path = PathBuf::from("uploads").join(name);
tokio::fs::write(&path, &buffer)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
saved.push(format!("{name}({written} bytes)"));
}
Ok((StatusCode::CREATED, saved.join(", ")))
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/upload", post(upload))
.layer(DefaultBodyLimit::max(MAX_BODY));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}Report a problem with this exampleOpens a pre-filled issue on GitHub.