概要
Rocket 提供最基礎的架構(gòu)來構(gòu)建rust服務端應用:剩下的取決于你自己。簡而言之咖为,Rocket提供路由,請求前置處理和相應后置處理稠腊。至于躁染,請求前置如何處理,相應后置如何處理架忌,請求如何處理吞彤,都是你的業(yè)務代碼決定的。
生命周期
Rocket的主要任務時監(jiān)聽新來的web請求叹放,分發(fā)這些請求到業(yè)務代碼饰恕,并且返回響應到客戶端。我們把從請求到響應的過程叫做生命周期井仰。我們把生命周期總結(jié)為一下幾個步驟:
- 路由
Rocket 會把新來的HTTP請求解析為你的代碼可以操作的rust結(jié)構(gòu)埋嵌。并且通過匹配你程序中聲明的路由屬性,來檢測俱恶,應該調(diào)用那個一個處理器雹嗦。 - 驗證
Rocket在匹配了路由以后就會對請求的數(shù)據(jù)做類型及有效性的驗證范舀。如果驗證失敗,則Rocket會把請求轉(zhuǎn)到下一個匹配的路由了罪,或者直接調(diào)用失敗處理器锭环。 - 處理器
請求的數(shù)據(jù)被驗證成功之后,會作為參數(shù)來調(diào)用綁定在路由上的處理器泊藕。作為應用的主要邏輯辅辩,在調(diào)用結(jié)束后,會返回一個響應娃圆。 - 響應
返回的響應也是被處理過的玫锋。Rocket 會生成合適的HTTP響應并且發(fā)送到客戶端。這樣一個生命周期就結(jié)束了踊餐。Rocket繼續(xù)監(jiān)聽新的請求景醇。并為每個請求創(chuàng)建一個生命周期。
這個章節(jié)剩余的部分會詳述路由部分和Rocket分發(fā)請求到請求處理器所需要的組件吝岭。之后的章節(jié)會詳述請求三痰、響應部分和Rocket的其它組件。
路由
Rocket應用都是以路由和處理器為中心窜管。路由由下列組成:
- 一組參數(shù)來匹配新來的請求散劫。
- 一個處理請求和返回響應的處理器。
處理器是一個簡單的函數(shù)幕帆,接受任意個數(shù)的參數(shù)并且返回任意類型的結(jié)果获搏。
用來匹配的參數(shù)包括靜態(tài)路徑、動態(tài)路徑失乾、路徑參數(shù)常熙、表單、查詢參數(shù)碱茁、特定的請求格式和 請求體數(shù)據(jù)裸卫。Rocket 利用屬性(類似其它語言的裝飾器一樣),使得路由聲明變得加單纽竣。路由聲明就是給處理器方法添加注解并且有一組參數(shù)用來匹配墓贿。一個完整的路由聲明是像這樣的:
#[get("/world")] // <- route attribute
fn world() -> &'static str { // <- request handler
"Hello, world!"
}
這個聲明了world
路由用來匹配靜態(tài)路徑"/world"
的GET
請求。"world"
路由比較簡單蜓氨,不過當構(gòu)建復雜的應用個的時候聋袋,額外的路由參數(shù)是必須的。請求 一節(jié)里面講解了構(gòu)建路由的所有情況穴吹。
掛載
在Rocket 能夠分發(fā)請求到一個路由之前幽勒,路由需要先完成掛載。 掛載路由港令,類似給路由一個命名空間代嗤。用 Rocket實例的mount方法來掛載一個路由棘钞。Rocket實例通常使用rocket::ignite()靜態(tài)方法來創(chuàng)建。
mount
方法需要:
- 一個包含一系列路由的命名空間的路徑干毅。
- 一組對應路由的處理器!和生成Rocket應用代碼的宏泼返。
例如硝逢,掛載之前聲明的world
路由,我們可以這樣寫:
rocket::ignite().mount("/hello", routes![world]);
這塊代碼通過 ignite 函數(shù)創(chuàng)建了一個新的Rocket實例绅喉,并且將 world
路由掛載到了“/hello” 路徑下面渠鸽。
其結(jié)果就是,GET請求 “/hello/world”路徑就會訪問world函數(shù)柴罐。
命名空間
當一個路由是在root之外的其它模塊里聲明的徽缚,你會在掛載的時候會得到一個異常:
mod other {
#[get("/world")]
pub fn world() -> &'static str {
"Hello, world!"
}
}
use other::world;
fn main() {
// error[E0425]: cannot find value `static_rocket_route_info_for_world` in this scope
rocket::ignite().mount("/hello", routes![world]);
}
這個錯誤出現(xiàn)是因為 宏 routes! 在生成Rocket代碼的時候隱式地將 route的名稱 轉(zhuǎn)換為了當前解構(gòu)里的名稱。解決方法是在寫路由名稱的時候加上模塊的名字:
rocket::ignite().mount("/hello", routes![other::world]);
運行
現(xiàn)在Rocket已經(jīng)有了路由革屠,你可以用launch方法來啟動Rocket接受請求凿试。launch用來方法啟動服務等待請求。當請求到達時似芝,Rocket 會找到匹配的路由那婉,并將請求分發(fā)到該路由的處理器。
通常情況下我們在main
方法里調(diào)用launch
方法〉澄停現(xiàn)在我們已經(jīng)完成了Hello, world!
程序详炬,看起來像這樣:
#![feature(plugin)]
#![plugin(rocket_codegen)]
extern crate rocket;
#[get("/world")]
fn world() -> &'static str {
"Hello, world!"
}
fn main() {
rocket::ignite().mount("/hello", routes![world]).launch();
}
注意到我們添加了#![feature(plugin)]
和 #![plugin(rocket_codegen)]
這兩行,是告訴Rust我們使用了Rocket的代碼生成插件寞奸。同樣我們將通過extern crate rocket
將 rocket
crate(箱)引入了我們的命名空間呛谜。最后,我們在main
函數(shù)里調(diào)用了launch
方法枪萄。
運行這個程序隐岛,控制臺會顯示內(nèi)容:
?? Configured for development.
=> address: localhost
=> port: 8000
=> log: normal
=> workers: [logical cores * 2]
=> secret key: generated
=> limits: forms = 32KiB
=> tls: disabled
?? Mounting '/hello':
=> GET /hello/world
?? Rocket has launched from http://localhost:8000
我們訪問 localhost:8000/hello/world
,就會看到Hello, world
, 正好是我們預期的。
在GitHub上有這個例子一個完整版的crate(箱)呻引,只要cargo run
就能運行礼仗。 你可以在 GitHub examples directory 中找到更多的例子,涵蓋了所有Rocket的特性逻悠。