在這個章節中,將會介紹Rocket框架處理JSON和MessagePack請求的方式,以及Rocket框架內建的處理UUID的做法,還有提供靜態檔案(如圖片檔、CSS、JS等等的靜態資源檔)的更好方式。
JSON
Rocket提供的serde::json::Json
結構體可以直接當作資料守衛或是路由處理程序的函式的回傳值型別,有關於回傳JSON
的用法會在之後的章節再做介紹。
若要使用serde::json::Json
結構體,必須要在Cargo程式專案的設定檔中啟用rocket
的json
特色,同時加入serde
這個crate,並啟用derive
特色。如下:
[dependencies]
serde = { version = "1", features = ["derive"] }
rocket = { version = "0.5.0", features = ["json"] }
有關於serde
的介紹可以參考這篇文章:
簡單來說,我們可以替自己實作出來的型別加上Deserialize
這個derive
屬性的參數,使這個型別的資料可以直接被Rocket框架反序列化。使用serde::json::Json
結構體來包裹可被serde
反序列化的資料型別,就可以將JSON字串直接反序列化成該型別了!而且我們可以把這個Json<T>
型別直接當作資料守衛來使用。
例如:
#[macro_use]
extern crate serde;
#[macro_use]
extern crate rocket;
use rocket::serde::json::Json;
#[derive(Deserialize)]
struct User {
id: i32,
name: String,
}
#[post("/", data = "<user>")]
fn handler(user: Json<User>) -> String {
format!("Hello, world! id = {}, name = {}", user.id, user.name)
}
#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![handler])
}
以上程式,當HTTP請求的主體中的資料是JSON格式的字串時,就會被反序列化為User
結構實體。
為了避免傳進來的JSON格式的字串太長,而導致反序列化需要耗費大量時間與記憶體,我們可以利用先前學過的Rocket框架的設定方式,在limits
設定項目中加入json
欄位來限制資料量。
MessagePack
Rocket提供的serde::msgpack::MsgPack
結構體可以直接當作資料守衛或是路由處理程序的函式的回傳值型別,有關於回傳MsgPack
的用法會在之後的章節再做介紹。
與serde::json::Json
結構體一樣,若要使用serde::msgpack::MsgPack
結構體,必須要在Cargo程式專案的設定檔中啟用rocket
的msgpack
特色,同時加入serde
這個crate,並啟用derive
特色。
使用rocket_contrib::msgpack::MsgPack
結構體來包裹可被serde
反序列化的資料型別,就可以將符合MessagePack格式的資料直接反序列化成該型別了!而且我們可以把這個MsgPack<T>
型別直接當作資料守衛來使用。
使用serde::msgpack::MsgPack
結構體來包裹可被serde
反序列化的資料型別,就可以將MessagePack格式的資料直接反序列化成該型別了!而且我們可以把這個MsgPack<T>
型別直接當作資料守衛來使用。
例如:
#[macro_use]
extern crate serde;
#[macro_use]
extern crate rocket;
use rocket::serde::msgpack::MsgPack;
#[derive(Deserialize)]
struct User {
id: i32,
name: String,
}
#[post("/", data = "<user>")]
fn handler(user: MsgPack<User>) -> String {
format!("Hello, world! id = {}, name = {}", user.id, user.name)
}
#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![handler])
}
以上程式,當HTTP請求的主體中的資料是MessagePack格式的資料時,就會被反序列化為User
結構實體。
為了避免傳進來的MessagePack格式的資料太長,而導致反序列化需要耗費大量時間與記憶體,我們可以利用先前學過的Rocket框架的設定方式,在limits
設定項目中加入msgpack
欄位來限制資料量。
UUID
Rocket提供的serde::uuid::Uuid
結構體可以直接當作查詢守衛或是資料守衛。
若要使用serde::uuid::Uuid
結構體,必須要在Cargo程式專案的設定檔中啟用rocket
的uuid
特色。
serde::uuid::Uuid
結構體的使用方式不難,例如以下程式:
#[macro_use]
extern crate rocket;
use rocket::{response::status, serde::uuid::Uuid};
#[get("/device/<uuid>/name")]
fn handler(uuid: Option<Uuid>) -> Result<&'static str, status::NotFound<&'static str>> {
match uuid {
Some(uuid) => match uuid.to_fields_le() {
(1692521986, 53139, 32579, [149, 69, 236, 56, 53, 249, 44, 216]) => {
// 02d6e164-93cf-437f-9545-ec3835f92cd8
Ok("Vacuum Cleaner")
},
(613895186, 12848, 3396, [160, 28, 6, 3, 61, 174, 199, 229]) => {
// 124c9724-3032-440d-a01c-06033daec7e5
Ok("Refrigerator")
},
_ => Err(status::NotFound("Unknown device")),
},
None => Err(status::NotFound("Incorrect UUID")),
}
}
#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![handler])
}
靜態檔案
在先前的章節中我們有提到可以使用區段守衛搭配Rocket內建的fs::NamedFile
結構體,來讓Rocket實現出提供檔案系統的某目錄下所有靜態檔案(如圖片檔、CSS、JS等等的靜態資源檔)的功能。但Rocket其實也有提供fs::FileServer
結構體來幫我們快速實作出這個功能,只要將fs::FileServer
結構實體透過Rocket
結構實體的mount
方法註冊給Rocket使用即可。
例如:
#[macro_use]
extern crate rocket;
use rocket::fs::FileServer;
#[launch]
fn rocket() -> _ {
rocket::build().mount("/public", FileServer::from("static"))
}
以上程式,可以使/public
這個路徑底下的相對路徑對應到Rocket應用程式的工作目錄中的static
目錄下的檔案。與使用路由處理程序的函數來回傳fs::NamedFile
時一樣,使用fs::FileServer
結構體也會在HTTP回應中自動加入Content-Type
欄位。這個Content-Type
欄位的值會根據網址路徑指到的檔案類型(依照檔案副檔名)而自動做適當的變化。
篩選HTTP請求的主體類型
Rocket框架可以依照HTTP請求中的Content-Type
欄位,使路由處理程序只允許某種特定類型的HTTP請求。要做到這件事,只需要在路由處理程序的HTTP請求方法的屬性中,加上format
參數,與data
參數搭配使用。
例如以下程式,可以使Rocket有能力對相同的路徑但不同資料類型的HTTP請求做不一樣的處理。
#[macro_use]
extern crate serde;
#[macro_use]
extern crate rocket;
use rocket::{
form::Form,
serde::{json::Json, msgpack::MsgPack},
};
#[derive(FromForm, Deserialize)]
struct User {
id: i32,
name: String,
}
#[post("/", format = "application/json", data = "<user>")]
fn handler_1(user: Json<User>) -> String {
format!("Hello, world! id = {}, name = {} (from JSON)", user.id, user.name)
}
#[post("/", format = "application/msgpack", data = "<user>")]
fn handler_2(user: MsgPack<User>) -> String {
format!("Hello, world! id = {}, name = {} (from MessagePack)", user.id, user.name)
}
#[post("/", format = "form", data = "<user>")]
fn handler_3(user: Form<User>) -> String {
format!("Hello, world! id = {}, name = {} (from Form)", user.id, user.name)
}
#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![handler_1, handler_2, handler_3])
}
format
參數不一定要寫出完整的MIME類型,以下是它的簡寫對應表:
MIME類型 | 簡寫 |
---|---|
application/octet-stream | binary |
application/json | json |
application/msgpack | msgpack |
application/x-www-form-urlencoded | form |
application/javascript | js |
text/html | html |
text/plain | plain |
text/css | css |
text/xml | xml |
multipart/form-data | multipart |
總結
這個章節介紹了Rocket框架與serde
框架結合起來處理HTTP請求的用法。下一個章節會先暫時拋開serde
,要來介紹Rocket框架的狀態(state)處理機制。
下一章:狀態(State)。