#actix-web #actix #web #parser #multipart

actix_extract_multipart

ActixExtractMultipart 是一个库,可以将 actix_multipart 解析为自定义的结构

11 个版本 (5 个稳定版本)

1.2.0 2022 年 8 月 15 日
1.1.1 2022 年 5 月 29 日
1.0.1 2021 年 11 月 7 日
1.0.0 2021 年 10 月 28 日
0.1.0 2021 年 5 月 28 日

#1572编码

Download history 1/week @ 2024-03-26 7/week @ 2024-04-02 1/week @ 2024-04-23 7/week @ 2024-04-30 20/week @ 2024-05-07 39/week @ 2024-05-14 2/week @ 2024-05-21

每月 85 次下载

MIT 许可证

31KB
597

ActixExtractMultipart

用于更轻松处理 actix 多部分的功能。您可以将多部分转换为结构。

要使用此函数,您需要创建一个具有 "Deserialize" 特性的结构,如下所示

#[derive(Deserialize)]
struct Example {
    string_param: String,
    optional_u_param: Option<u32>,
    files_param: Option<Vec<File>>
}

File 是任何文件的结构

#[derive(Debug, Deserialize)]
pub struct File {
    file_type: String,
    name: String,
    data: FileData,
}
impl File {
    pub fn file_type(&self) -> &String {
        &self.file_type
    }
    pub fn name(&self) -> &String {
        &self.name
    }
    pub fn len(&self) -> usize {
        self.data.len()
    }
    pub fn data(&self) -> &FileData {
        &self.data
    }
}

FileData 是 Vec bytes 的别名

pub type FileData = Vec<u8>;

使用示例

use actix_web::{post, App, HttpResponse, HttpServer};
use serde::{Deserialize};
use actix_extract_multipart::*;

#[derive(Deserialize)]
struct Example {
    string_param: String,
    optional_u_param: Option<u32>,
    file_param: File
}

fn saving_file_function(file: &File) -> Result<(), ()> {
    // Do some stuff here
    println!("Saving file \"{}\" successfully", file.name());

    Ok(())
}

#[post("/example")]
async fn index(example_structure: Multipart::<Example>) -> HttpResponse {    
    println!("Value of string_param: {}", example_structure.string_param);
    println!("Value of optional_u_param: {:?}", example_structure.optional_u_param);
    println!("Having file? {}", match example_structure.file_param {
        Some(_) => "Yes",
        None => "No"
    });

    if let Some(file) = &example_structure.file_param {
        match saving_file_function(&file) {
            Ok(_) => println!("File saved!"),
            Err(_) => println!("An error occured while file saving")
        }
    }

    HttpResponse::Ok().json("Done")
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    println!("Server run at http://127.0.0.1:8080");

    HttpServer::new(move || {
        App::new()
            .service(index)
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

在此示例中,如果您没有收到文件,extract_multipart 将返回 Err(_),因为数据与 "Example" 数据结构不匹配。如果文件是可选的,您可以简单地设置类型为 Option,如下所示

#[derive(Deserialize)]
struct Example {
    string_param: String,
    optional_u_param: Option<u32>,
    file_param: Option<File>
}

对于 Vec,不要忘记在字段名末尾放置挂钩。您还可以使用任何其他类型数组,如 Vec 等。在以下 HTML 示例中,您会注意到文件的字段名包含挂钩:name="files_param[]"。这是非常重要的,如果没有挂钩,此代码将无法工作。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Testing</title>
    <script>
        function send() {
            let myHeaders = new Headers();
            let formdata = new FormData(document.getElementById('form'));
            let myInit = { method: 'POST', headers: myHeaders, body: formdata };
            fetch("http://127.0.0.1:8082/example", myInit)
            .then(() => {
                console.log("It works!")
            })
            .catch((e) => {
                console.log("Error!\n" + e)
            })
        }
    </script>
</head>
<body>
    <form id="form">
        <input type="file" name="files_param[]" multiple>
        <button type="button" onclick="send()">OK</button>
    </form>
</body>
</html>

依赖项

~15–26MB
~459K SLoC