我正在与 Rust 和 Rocket 合作。我有一个端点可以一次上传一个文件form-data:
use rocket::form::{Form, FromForm};\nuse rocket::fs::TempFile;\nuse std::ffi::OsStr;\nuse std::path::{Path};\nuse uuid::Uuid;\n\n#[post("/file_upload", format = "multipart/form-data", data = "<form>")]\npub async fn file_upload(mut form: Form<Upload<\'_>>) -> std::io::Result<String> {\n // Get raw file \n let file_name = form.file.raw_name().unwrap().dangerous_unsafe_unsanitized_raw().as_str();name\n // Get extension of file name\n let extension = Path::new(file_name).extension().and_then(OsStr::to_str).unwrap(); \n // Generate new UUID\n let id: String = Uuid::new_v4().to_string(); \n // Build path to save file\n let file_path = String::from("media/temp_files") + "/" + &id + "." + extension; \n\n // Save file\n form.file.persist_to(file_path).await?; \n\n Ok(String::from("Ok"))\n}\nRun Code Online (Sandbox Code Playgroud)\n这可行,但我将持久性、业务逻辑和 HTTP 基础设施混合在同一个模块中。我只想依靠 Rocket 来检索文件流和元数据(文件名、大小和内容类型),并将其传递给另一个负责验证、图像处理等的函数。
\n我可以访问元数据,但我不知道如何从结构中检索缓冲内容TempFile。
// rocket-0.5.0-rc.2/src/fs/temp_file.rs\n[\xe2\x80\xa6]\npub enum TempFile<\'v> {\n #[doc(hidden)]\n File {\n file_name: Option<&\'v FileName>,\n content_type: Option<ContentType>,\n path: Either<TempPath, PathBuf>,\n len: u64,\n },\n #[doc(hidden)]\n Buffered {\n content: &\'v str,\n }\n}\n[\xe2\x80\xa6]\nRun Code Online (Sandbox Code Playgroud)\n我没有看到任何方法返回它。是否缺少任何方法来检索原始文件内容?或者 Rocket 中可能有不同的结构/特征来实现这一点。
\n只是我的评论的后续内容可以回答您的问题。
@badoken 似乎在这里提交了 PR:https ://github.com/SergioBenitez/Rocket/pull/2361
TempFile基本上这允许像这样传递结构:
#[derive(FromForm)]
struct MyForm<'r> {
foo: &'r [u8],
}
Run Code Online (Sandbox Code Playgroud)
我仍然不确定如何从中获取元数据。我必须进一步测试并改进这个答案。
编辑:经过一番挖掘,我有以下适合我的需求的解决方案。
use rocket::form::{DataField, Form, FromFormField};
use rocket::http::{ContentType, CookieJar, Status};
use rocket::{FromForm, post};
use rocket::data::ToByteUnit;
use rocket::fs::{FileName};
use rocket::response::content::RawHtml;
use crate::utils::Md5;
pub struct File<'v> {
file_name: Option<&'v FileName>,
content_type: ContentType,
data: Vec<u8>,
}
#[rocket::async_trait]
impl<'v> FromFormField<'v> for File<'v> {
async fn from_data(field: DataField<'v, '_>) -> rocket::form::Result<'v, Self> {
let stream = field.data.open(u32::MAX.bytes());
let bytes = stream.into_bytes().await?;
Ok(File {
file_name: field.file_name,
content_type: field.content_type,
data: bytes.value,
})
}
}
#[derive(FromForm)]
pub struct UploadRequest<'r> {
file: File<'r>,
}
#[post("/upload", data = "<req>")]
pub async fn upload(
content_type: &ContentType,
req: Form<UploadRequest<'_>>,
cookies: &CookieJar<'_>,
) -> Result<RawHtml<String>, Status> {
Ok(RawHtml(format!("file: {}, md5: {}, content-type: {} / {}",
req.file.file_name.unwrap().as_str().unwrap_or("Frack") ,
&req.file.data.md5(),
content_type,
req.file.content_type
)))
}
Run Code Online (Sandbox Code Playgroud)
当在端点中推送小视频文件时/upload,我得到以下结果:
file: 1ae366a5-209e-4b5e-8d37-826db09090fb, md5: ae78f71db09cb7ae26607f0bd7e917a3, content-type: multipart/form-data;
boundary=--------------------------248453579191145706333860 / video/mp4
Run Code Online (Sandbox Code Playgroud)
文件名的扩展名丢失,但其类型位于文件content_type字段中。
md5 哈希确保文件未被更改。
| 归档时间: |
|
| 查看次数: |
1071 次 |
| 最近记录: |