Rocket使用小結
2019-04-08: 本文亦在我的新博客中
(本文亦在我的wikiblog中)
在今年Increase Rust's Reach中,我參與Rust新網站的i18n及l10n。其中新網站要基於Rocket構建,所以也就(跟着官方教程)學習了一下Rocket。 既然學了,就順便記錄一點心得和體會,以方便後來者。
Rocket是一個 web框架 。我個人對web編程(尤前端)並不太感興趣(主要是感到 web技術棧 太過麻煩/複雜),所以涉及不太多,之前也只用過Python那邊的Flask以及(一小段時間)Django以及Go自帶的http服務器,故而本文不怎麼會涉及和其他web框架的對比。
本文不打算成爲通常意義上的Rocket教程,而只是打算給有興趣者一個快速的(對rocket的)觀感。其中也會有一些個人的經驗教訓等。
Rocket概覽
類似我之前用過的框架,Rocket也將函數作爲不同的路由的處理器。Rocket在每個函數之前使用形如#[get("/myroute")]
的 屬性 作爲標記,之後在Rocket入口對象/結構體上對所需要的路由(函數)進行mount
即可。
#[get("/")]
fn index() -> &'static str {
"Hello, world!"
}
fn main() {
rocket::ignite()
.mount("/", routes![index])
.launch();
}
(代碼片段來自這裏。)
這點粗看很像Flask中使用@app.route()
進行路由設定,僅有這兩點不同:
- Rocket不使用全局的app對象
- 路由可以定義但不掛載
我最初也以爲Rocket和Flask的設計極爲相似,且兩者都只打算做web框架而不涉及其他;然而,越到後面越是發現兩者不同之處的巨大。相對而言,我個人更喜歡Rocket的設計:更加函數導向(亦強調使用局部變量)。
-
在Rocket中,函數是處理路由的全部,不需要使用如flask中魔法一般的全局
request
對象; - 函數的參數和屬性中的設定共同決定了路由是否匹配,手動類型的優勢在這裏有所體現;
- 各種(預定義或自定義的) 請求哨衛 可以被添加到函數參數表中參與決定路由的匹配性;
- 使用 整流器 在請求到達前或應答發送時對請求或應答進行調整;
-
使用
State
做狀態存儲,以便的確需要“全局”變量的情況。
路由匹配
Rocket通過在屬性上設定不同的HTTP方法以及URL段來做匹配。 具體細節見官方文檔,這裏僅做摘要:
- 常見HTTP方法均被支持,只是每次只能設定一個方法
- 在未定義時,HEAD請求會被自動轉到相應的GET請求上(不過會刪除應答體)
-
表單首個字段爲
_method
時,POST請求會被自動重譯爲相應的請求- 該設定是爲了方便瀏覽器,畢竟瀏覽器通常只有GET和POST
在路由的URL上,可以設定將部分(或全部) 節 注入到函數的對應參數中。Rocket會自動進行類型轉換,且僅匹配轉換成功的路由。
#[get("/hello/<name>/<age>/<cool>")]
fn hello(name: String, age: u8, cool: bool) -> String {
if cool {
format!("You're a cool {} year old, {}!", age, name)
} else {
format!("{}, we need to talk about your coolness.", name)
}
}
(代碼片段來自這裏。)
自定義類型也可用在路由匹配中,只要其實現了FromParam
trait即可。
請求及應答
在不考慮整流器的情況下,用戶的請求將直接進入相應的路由函數中,然後經過函數的處理,最後函數的返回值將作爲應答。路由匹配的過程即是請求處理器的選擇過程。
Rocket不要求路由函數的返回值是一個HTTP應答(Response
),而是通過Responder
機制方便編程:路由函數的返回值需要是一個實現了Responder
trait的類型,而Rocket負責調用Responder
的相關函數將路由函數的返回值轉換爲HTTP應答。這樣,在Rocket中我們便可以用String
等類型作爲函數返回值。
Rocket提供一些實現以應對常見的應答情況:
-
應答包裝器 可以包含其他
Responder
,並且執行自己的修改 -
String
和&str
會被作爲應答體,且Content-Type會被設置爲text/plain
-
Option
是應答包裝器,Option<T>
的T
需要實現Responder
:-
當是
Some
時,其內容將會被作爲應答 -
當是
None
時,返回404
-
當是
-
Result
是應答包裝器,且其功能取決於E
是否實現Responder
:-
若
E
實現了Responder
,則該Result
會被作爲應答(無論是Ok
還是Err
) -
若
E
沒有實現Responder
,則Ok
會被作爲應答,但Err
會被記錄在終端中且返回500
-
若
(官方文檔中還列出了幾個常見的對於HTTP很有意義的Responder
實現,包括下面所說的Template
。)
網頁模板
作爲一個web框架,提供對網頁模板的支持幾乎是理所應當。Rocket本身提供了Template
機制,而在rocket_contrib
crate中提供了一些特定模板支持。
Template
被實現爲一個Responder
,這樣讓響應函數返回Template
類型即可:
#[get("/")]
fn index() -> Template {
let context = /* object-like value */;
Template::render("index", &context)
}
Rocket不限制使用何種模板,但官方文檔提到了.hbs
Handlebars和.tera
Tera。而Rocket的Template
機制之所以有效,還需要整流器的幫助——所以需要在Rocket實例上.attach(Template::fairing());
以便可以正確使用模板。
整流器
依Rocket文檔所說,整流器的功能類似於中間件,可以介入請求和應答過程以進行額外操作。由於我沒有學過相關課程,也沒有太多瞭解相關知識,所以無法給出個人對此的看法,只能照搬官方文檔的說法。
在類似其他框架的中間件之外,Rocket對整流器的功能有一些額外規定:
- 整流器不能終止或直接響應請求
- 整流器不能任意注入非請求數據至請求中
- 整流器可以阻止程序的啓動
- 整流器可以修改程序的配置
官方文檔對整流器有更多說明,但對我來說最需要知道的還有這些:
- 整流器應當只用於“全局”適用的東西(比如做日誌)
- 更多時候,需要的其實是 請求哨衛 和 數據哨衛
-
整流器按順序執行,所以
.attach()
的順序需要注意
全局共享數據
這裏的“全局”指的是Rocket之內,在各個路由中共享數據。由於路由是由Rocket管理的,故而其參數表中沒辦法添加更多參數;而Rust又沒有全局變量(即使有也不符合美感),故而Rocket提供的 狀態 機制可謂實用非常。Rocket官方教程中也教導使用狀態來管理數據庫連接。
使用上,狀態同樣通過 請求哨衛 機制,作爲路由函數的參數。任何類型的數據均可作爲State
,且不需要額外實現任何東西。唯一的要求就是在Rocket實例載入時要求管理該狀態。
像這樣要求Rocket去管理某個狀態:
struct HitCount {
count: AtomicUsize
}
rocket::ignite()
.manage(HitCount { count: AtomicUsize::new(0) });
像這樣要求在某路由函數上使用某狀態:
#[get("/count")]
fn count(hit_count: State<HitCount>) -> String {
let current_count = hit_count.count.load(Ordering::Relaxed);
format!("Number of visits: {}", current_count)
}
#[get("/state")]
fn state(hit_count: State<HitCount>, config: State<Config>) -> T { ... }
需要注意的是,Rocket對每種數據類型管理一個狀態,而不是每個數據。
另外,在自定義的 請求哨衛 中,也可以使用狀態:
fn from_request(req: &'a Request<'r>) -> request::Outcome<T, ()> {
let hit_count_state = req.guard::<State<HitCount>>()?;
let current_count = hit_count_state.count.load(Ordering::Relaxed);
...
}
(代碼片段來自這裏。)
總結
總得來說,我個人對Rocket的設計較爲欣賞/膜拜,尤其是其對Rust各項機制的有效利用。
之前用其他框架時總有覺得彆扭的地方,但它們均不存在於Rocket中,讓我寫起來覺得比較順手:
-
Django(2013年底或2014年初)
- 框架內耦合性太強,但框架的手又過長
-
什麼都想讓框架承包,初學者用起來束手束腳
- 當然,也可以說是我還沒有體會到Django的好處。但我實在是對封閉花園式的東西感到反感,所以不見得可以體會到Django的妙處
- 而且當年對Py3的支持還不怎麼樣,但我又恰恰想用Py3
-
Go(2015年)
- Go的自帶http庫直接將請求和應答對象作爲參數傳入,手動解析很難受
- Go的html模板是語言提供的,靈活度上讓我懷疑
- 當時(2015年)查過其他的go語言web框架,比較看好的有beego以及另一個想不起來名稱的。但其教程寫得並不如人意(不如我意),又由於當年需求十分簡單,所以直接裸上語言庫
-
Flask(2016年)
- Flask要使用全局的app對象和db對象,設計上很詭異
-
Flask要使用魔法一般的request對象,總讓人覺得不安心
- 且request對象暴露太多內容,類似Go用http庫的感覺(和使用Android的Context對象的感覺很像)
然而,我對Rocket的部分trait和/或類型設計仍有疑惑,還在尋找解決方案的過程中。 另外,我暫時還沒有在Rust中使用過數據庫連接,所以無法對其聯合使用後的手感做出評價。 但綜合來看,Rocket的設計可以說是我所用過的所有框架中最符合我心意的框架;而且它的設計理念可以說符合了我對web框架所構想的所有主要要求。如果不是因爲Rust仍算小衆,Rocket的用戶量和教程量應當早就超過現有的數量了吧(2018-08-02 Google搜“Rust Rocket 教程”,得到11,200條結果)。
- 无匹配
2022年8月09日 11:26
The new online web source portal2.bsnl.in provided by Bharat Sanchar Nigam Limited allows loyalty rewards for each online transaction towards landline, mobile, broadband, BSNL Landline Bill Payment fiber optic internet (FTTH) before or after the due date and even after disconnection. Check the new process in step by step to pay BSNL bill quickly in online without login using credit card or debit card or internet banking payment.The new online web source portal2.bsnl.in provided by Bharat Sanchar Nigam Limited allows loyalty rewards for each online transaction towards landline, mobile, broadband.
2023年5月19日 07:45
collaborate on news coverage of the most recent events in India. Our team is made up of professional writers and citizen journalists with a wide range of journalism interests who are passionate about delivering education updates in the public interest and with transparency is a project badi9.in of experienced writers who have gathered for specialised news coverage of recent events across the nation (India). Our team is made up of professional writers and citizen journalists with a wide range of journalism interests who are committed about delivering education updates in the public interest while maintaining transparency.
2024年1月27日 17:54
JNANABHUMI AP provides a CBSE syllabus for all classes for the academic year 2024 has been designed as per the guidelines of the CBSE Board. The syllabus offers a conceptual background and lays the groundwork for the Class 10 Board exams. jnanabhumiap.in By visiting the page, students will find the downloadable pdf of the reduced CBSE 10th Syllabus along with the deleted portion of the syllabus for each subject. So, students are advised to prepare for the exam, as per the syllabus mentioned here.