rocket实现文件单/多文件上传

单文件和多文件html的区别就是multiple

toml

[dependencies]
rocket = "0.5.1"
[package.metadata.rocket]
config = "Rocket.toml" 

Rocket.toml 配置文件上传的大小限制

# Rocket.toml

[default.limits]
form = "160MB"  # 设置文件上传的最大大小为16MB
data-form = "160MB"
file = "160MB"
[development.limits]
form = "160MB"  # 设置文件上传的最大大小为16MB
data-form = "160MB"
file = "160MB"

[production.limits]
form = "160MB"  # 设置文件上传的最大大小为16MB
data-form = "160MB"
file = "160MB"

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>File Upload</title>
</head>
<body>
<h1>Upload a File</h1>
<!-- 表单的 action 指向你的 Rocket 应用的 '/upload' 路由 -->
<!-- 表单的 enctype 设置为 "multipart/form-data" 以支持文件上传 -->
<form action="http://127.0.0.1:8000/upload" method="post" enctype="multipart/form-data">
    <!-- 文件输入字段 -->
     <!-- 单文件不需要multiple -->
    <input type="file" name="file" id="file" multiple><br><br>
    <!-- 提交按钮 -->
    <input type="submit" value="Upload File">
</form>
</body>
</html>

单文件rs

use rocket::{routes,
             post,
             fs::TempFile,
             form::FromForm,
             form::Form,
             http::Status,
};
use std::path::{Path};

#[derive(FromForm)]
struct Upload<'f> {
    file: TempFile<'f>,
}

#[post("/", format = "multipart/form-data", data = "<form>")]
async fn upload_file(mut form: Form<Upload<'_>>) -> Result<String, Status> {
    // 直接从 Option<FileName> 中提取文件名并转换为 String,但是这种是没有后缀的,被优化过的
    // let file_name =  match  form.file.name() {
    //     Some(s) => s,
    //     None => "None-0"  //可以用uuid
    // };
    // // 从 Path 中提取文件名,包括后缀名
    //  let file_path = form.file.path().ok_or(Status::InternalServerError)?;
    //  let path = Path::new(file_path); // 将路径转换为 Path 类型
    //  let file_name1 = path.file_name().ok_or(Status::InternalServerError)?.to_str().ok_or(Status::InternalServerError)?.to_string();
    //  println!("File name with extension: {}", file_name1); // 打印完整的临时文件名
    //取出上传的时候的老的文件名
    let file_name = form.file.raw_name().map(|name| name.dangerous_unsafe_unsanitized_raw().as_str())
        .unwrap_or_else(|| "default_filename.pdf"); // 如果没有文件名,则使用默认值
    println!("{}", file_name);
    //获取是json jpg png zip 。。。。。
    //let extension =  form.file.content_type().map(|s| s.media_type().sub().to_string());
    //println!("{:?}", extension);
    //打印tmp_path目录
    let tmp_path = Path::to_str(form.file.path().unwrap()).map(|s| s.to_string()).unwrap();
    println!("{}", tmp_path);
    // 确保上传目录存在
    let upload_dir = "uploads"; // 你可以根据需要修改这个路径
    std::fs::create_dir_all(upload_dir).map_err(|_| Status::InternalServerError)?;
    // 尝试将文件保存到服务器
    let upload_path = std::path::Path::new(upload_dir).join(file_name); // 使用 join 方法将目录和文件名组合成 Path
    if form.file.copy_to(upload_path.clone()).await.is_ok() {
        // 文件上传成功后的逻辑
        //删除临时目录的文件
        std::fs::remove_file(tmp_path).map_err(|_| Status::InternalServerError)?;
        Ok(format!("上传成功 {}", upload_path.display()))
    } else {
        Err(Status::InternalServerError)
    }
}

#[rocket::main]
async fn main() -> Result<(), rocket::Error> {
    rocket::build()
        .mount("/upload", routes![upload_file])
        .launch()
        .await?;

    Ok(())
}

多文件

use rocket::{routes,
             post,
             fs::TempFile,
             form::FromForm,
             form::Form,
             http::Status,
};
use std::path::{Path};

#[derive(FromForm)]
struct Upload<'f> {
    file: Vec<TempFile<'f>>,
}

#[post("/", format = "multipart/form-data", data = "<form>")]
async fn upload_file(mut form: Form<Upload<'_>>) -> Result<String, Status> {
    let upload_dir = "uploads";
    std::fs::create_dir_all(upload_dir).map_err(|_| Status::InternalServerError)?;
    // 遍历 form.files 并使用 iter_mut 获取每个文件的可变引用
    for temp_file in form.file.iter_mut() {
        // 取出上传时的原始文件名
        let file_name = temp_file.raw_name()
            .map(|name| name.dangerous_unsafe_unsanitized_raw().as_str())
            .unwrap_or_else(|| "default_filename.pdf"); // 如果没有文件名,则使用默认值
        println!("{}", file_name);

        let upload_path = Path::new(upload_dir).join(file_name.to_string());
        let tmp_path = Path::to_str(temp_file.path().unwrap()).map(|s| s.to_string()).unwrap();
        println!("{}", tmp_path);
        // 尝试将文件保存到服务器
        if !temp_file.copy_to(upload_path.clone()).await.is_ok() {
            std::fs::remove_file(tmp_path).map_err(|_| Status::InternalServerError)?;
            return Err(Status::InternalServerError);
        }
    }
    Ok(format!("上传成功"))
}

#[rocket::main]
async fn main() -> Result<(), rocket::Error> {
    rocket::build()
        .mount("/upload", routes![upload_file])
        .launch()
        .await?;

    Ok(())
}

纯文本上传

#[post("/upload2", format = "text/plain", data = "<file>")]
async fn upload(mut file: TempFile<'_>) -> std::io::Result<()> {
    let permanent_location = PathBuf::from("F:\\code\\rocket-upload\\uploads\\11.txt");
    file.copy_to(permanent_location).await
}

postman模拟纯文本上传,写入文件

在Body部分,选择raw选项,然后在右侧的下拉菜单中选择plain类型或者text类型。
posted @ 2024-10-30 11:16  朝阳1  阅读(19)  评论(0编辑  收藏  举报