Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

文件上传

AFast 通过 multer crate 支持 multipart/form-data 文件上传。提供两种提取模式:

原始 Multipart (Multipart)

直接访问 multipart 流:

#![allow(unused)]
fn main() {
use afast::{post, Multipart, HttpResult, Json, Tag};
use serde::Serialize;

#[derive(Serialize, Tag)]
#[tag("上传结果")]
struct UploadResult {
    filename: String,
    size: usize,
}

#[post(desc("上传文件"))]
async fn upload(mut form: Multipart) -> HttpResult<Json<UploadResult>> {
    let field = form.next_field().await?.ok_or_else(|| {
        afast::Error::custom(400, "未提供文件")
    })?;
    let filename = field.file_name().unwrap_or("unknown").to_string();
    let data = field.bytes().await?;
    Ok(Json(UploadResult { filename, size: data.len() }))
}
}

类型化提取 (MultipartForm<T>)

使用 #[derive(FromFormData)] 自动提取到结构体:

#![allow(unused)]
fn main() {
use afast::{post, MultipartForm, FileField, HttpResult, Json, Tag, FromFormData};
use serde::Serialize;

#[derive(FromFormData, Tag)]
#[tag("上传表单")]
struct UploadForm {
    description: String,
    file: FileField,
}

#[derive(Serialize, Tag)]
#[tag("上传结果")]
struct UploadResult {
    filename: String,
    description: String,
    size: usize,
}

#[post(desc("带表单数据的上传"))]
async fn upload_typed(form: MultipartForm<UploadForm>) -> HttpResult<Json<UploadResult>> {
    let data = form.0;
    Ok(Json(UploadResult {
        filename: data.file.filename.unwrap_or_else(|| "unknown".to_string()),
        description: data.description,
        size: data.file.bytes.len(),
    }))
}
}

#[derive(FromFormData)]

该 derive 宏自动实现 FromFormData trait。每个结构体字段名必须与对应的表单字段名匹配。

支持的字段类型

Rust 类型表单字段说明
String文本字段直接文本值
i8/i16/i32/i64/u8/u16/u32/u64/f32/f64文本字段从文本解析
bool文本字段"true"/"false"/"1"/"0"
FileField文件字段收集字节、文件名、内容类型
Option<T>可选字段缺失时默认为 None

FileField 结构

#![allow(unused)]
fn main() {
pub struct FileField {
    pub name: String,                // 表单字段名
    pub filename: Option<String>,    // 原始文件名
    pub content_type: Option<String>, // MIME 类型
    pub bytes: Vec<u8>,              // 文件内容
}
}

客户端代码生成

TS/JS/KT 代码生成器自动生成基于 FormData 的上传代码:

// 生成的 TypeScript 客户端
const formData = new FormData();
formData.append('description', 'My file');
formData.append('file', new Blob(['content']), 'test.txt');
const result = await client.apis.upload_typed({ body: formData });

使用 curl 测试

# 原始上传
curl -F "file=@test.txt" http://localhost:5001/upload

# 带多个字段的类型化上传
curl -F "description=我的文件" -F "file=@test.txt" http://localhost:5001/upload/typed
已复制到剪贴板!