Rocket.rs 初探 - 接受透過 Base64 編碼的文件上傳
在這篇文章中,將 Rocket.rs 中如何上傳透過 Json 格式包裝的 Base64 編碼的文件, 並儲存至伺服器的指定資料夾中。
在一個 Web 應用程式中,傳送非純文字資料,如:圖片、檔案等是很常見的操作,但是在一個以 JSON 為導向的 API 設計中,我們會希望可以透過 JSON 來傳送這些檔案,在這篇文章會有如何將文件轉成 base64 上傳並在後端重新轉換回文件並寫入資料:
前置動作
安裝依賴套件
# Cargo.toml
# 這個相依負責 Encode 或 Decode base64 編碼的資料
[dependencies.base64]
version="0.12.3"
# 這個相依負責將 vec[u8] 等資料寫入文件中
[dependencies.file]
version="1.1.2"
# 這個文件負責產生隨機字串用於檔案名稱
[dependencies.rand]
version = "0.7.3"
# 用於檢查送上來的 Base64 image 的格式
[dependencies.regex]
version = "1"
範例
因為後端接收的是 Json 資料,如果還不知道怎麼在 Rust 中處理 Json 可以先參照:Rocket.rs 初探 - Json Request 和 Json Response 這篇文章,裡面有範例。
extern crate file;
use base64::{encode, decode};
use rand::{self, Rng};
use rand::distributions::Alphanumeric;
use regex::Regex;
#[derive(Debug, Serialize, Deserialize)]
struct UploadedImage {
// 用於儲存 base64 編碼的檔案
data: String
}
#[post("/images", format = "json", data="<image>")]
fn upload_image(image: Json<UploadedImage>) -> String {
// 檢查格式
let re = Regex::new(r"^data:image/jpeg;base64,[a-zA-Z0-9+/=]+$").unwrap();
if !re.is_match(image.data.as_str()) {
return String::from("File format invalid");
}
// 因為 base64 格式的會以 data:[MIME_TYPE];base64,來作為開頭
// 但是前面是必要資料,其中包含檔案的 MIME_TYPE
// 所以我們把 ;base64, 作為切分資料的依據
// 此外也可以僅用 , 作為切分依據,
// 因為 base64 的字元集僅包含:26個大小寫字母、10個數字,
// 以及加號(+)、斜槓(/) 還有等號(=)
let image_data = image.data.split(";base64,");
let vec: Vec<&str> = image_data.collect();
// 這邊第 2 個 element 就會是 base64 的資料
let image_bytes = base64::decode(vec[1]).unwrap();
// 取得當前位置
let mut filename = String::from(std::env::current_dir().unwrap().into_os_string().into_string().unwrap());
// 上傳的資料夾
filename.push_str("/images/");
// 文件名稱
let file_key = rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(10)
.collect::<String>();
filename.push_str(file_key.as_str());
filename.push_str(".jpg");
// 寫入指定檔案,寫入至<CURRENT_DIR>/images/<RANDOM_STRING>.jpg
file::put(filename, &image_bytes);
return String::from("Upload successful");
}
fn main() {
rocket::ignite().mount("/", routes![
upload_image
]).launch();
}
接著你可以試著向/images
發起POST
請求:
{
"data": "data:image/jpg;base64,..."
}
這樣就可以上傳到指定current_dir
底下的images
了。