axum 上传文件

984496
2021/11/13 08:17:32

文件上传是 Web 开发中常见的功能,本章将演示如何在 axum 实现文件上传。

启用 feature

要让 axum 支持文件上传,需要在 Cargo.toml 中显式的启用名为multipart的 feature:

文件上传表单

首先,我们定义文件上传表单:

注意,要使用文件上传,必须将<form>enctype设置为multipart/form-data

处理上传

/// 上传操作
async fn upload_file_action(
    ContentLengthLimit(mut multipart): ContentLengthLimit<Multipart, { MAX_UPLOAD_SIZE }>,
) -> Result<(HeaderMap, String), String> {
    if let Some(file) = multipart.next_field().await.unwrap() {
        let filename = file.file_name().unwrap().to_string(); // 上传的文件名
        let data = file.bytes().await.unwrap(); // 上传的文件的内容

        // 保存上传的文件
        //std::fs::write(&filename, &data).map_err(|err| err.to_string())?;
        tokio::fs::write(&filename, &data)
            .await
            .map_err(|err| err.to_string())?;

        return cn(format!(
            "【上传的文件】文件名:{:?}, 文件大小:{}",
            filename,
            data.len()
        ))
        .await;
    }
    cn(String::from("没有上传文件")).await
}

注意这个函数的参数:ContentLengthLimit(mut multipart): ContentLengthLimit<Multipart, { MAX_UPLOAD_SIZE }>

  • ContentLengthLimitMultipart 都是 axum 提供的extract。前者用于限制 HTTP 内容的长度,后者用于处理multipart/form-data

  • 获取到的变量是mut

首先,我们通过multipart.next_field()获取到提交过来的(下一个)type="file"的表单域。由它的方法名可知,它支持多文件上传。

然后,我们通过相关方法获取到上传文件的信息:

  • file_name():获取上传的文件的文件名

  • bytes():获取上传的文件的内容

最后,将上传的文件保存到服务器上:

tokio::fs::write(&filename, &data)
            .await
            .map_err(|err| err.to_string())?;

我们使用了tokio提供的异步 API,将上传的内容保存到服务器。

本章讨论了在 axum 实现文件上传功能,完整代码可以在我们的代码库中找到。