- 簡介
- hello world
- 常用功能
- 動態路徑
- 多個片段(segments)
- 靜態檔案伺服器
- 簡單WebAPI示例
- 新增依賴
- 實現介面
- 介面測試
- 參考連結
簡介
Rust中最知名的兩個web框架要數Rocket和Actix了,Rocket更注重易用性,Actix則更注重效能。這裡只是瞭解一下Rust下的WebAPI開發流程,就學一下最簡單的 Rocket。
Rocket 是一個用於 Rust 的非同步 Web 框架,專注於可用性、安全性、可擴充套件性和速度:
github:https://github.com/rwf2/Rocket/tree/v0.5
官網:https://rocket.rs
hello world
需要最新版本的 Rust 來執行 Rocket 應用程式,執行以下命令確保安裝了最新的工具鏈:
rustup default stable
建立一個新的基於二進位制的 Cargo 專案並切換到新目錄:
cargo new hello-rocket --bin
cd hello-rocket
執行以下命令,新增 Rocket 依賴項:
cargo add rocket
在 src/main.rs 檔案中新增以下程式碼:
#[macro_use] extern crate rocket;
#[get("/")]
fn index() -> &'static str {
"Hello, world!"
}
#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![index])
}
上面hello world示例沒有main函式,main函式由launch宏生成,可以透過原始碼看出:
pub fn launch(args: TokenStream, input: TokenStream) -> TokenStream {
emit!(attribute::entry::launch_attribute(args, input))
}
//...
async_entry!(launch_attribute, launch::Launch, quote!(fn main() {}));
執行程式,訪問 http://localhost:8000 以檢視應用,VS終端輸出如下:
程式帶的有彩色輸出,如果在資料夾手動開啟後沒有彩色輸出,說明系統不支援ANSI轉義序列。
常用功能
動態路徑
動態路徑比較常見的場景是動態id場景,可以傳N個動態型別即動態路徑有多層,只要這個型別實現了FromParam:
//訪問連結示例:http://localhost:8000/hello/張三/25/true
#[get("/hello/<name>/<age>/<is_male>")]
fn hello(name: &str, age: u8, is_male: bool) -> String {
if is_male {
format!("姓名 {} ,年齡 {}, 性別 男!", name, age)
} else {
format!("姓名 {} ,年齡 {}, 性別 女!", name, age)
}
}
這個路由會匹配所有/hello/為基礎路徑的路由,然後將它匹配到的動態路徑作為引數傳遞給處理器,Rocket預設給標準庫裡的一些常見型別以及Rocket自身的一些特殊型別實現了FromParam trait。
多個片段(segments)
可以透過<param..>的方式來匹配多個動態路徑,這種型別的引數一般被叫做分段防護裝置(segments guards),都必須先實現FromSegments這個trait。
use std::path::PathBuf;
//訪問連結示例:http://localhost:8000/page/foo/bar
#[get("/page/<path..>")]
fn get_page(path: PathBuf) -> String {
let mut output = String::new();
for part in path.iter() {
let part_str = part.to_string_lossy();
println!("路徑引數: {}", part_str);
output.push_str(&format!("路徑引數: {}\n", part_str));
}
output
}
PathBuf實現了FromSegments這個trait,所以不用擔心/page或者/page//導致的解析失敗,也不用擔心路徑遍歷攻擊(path traversal attacks)。
靜態檔案伺服器
基於 分段防護裝置(segments guards),可以簡單的實現一個安全的靜態檔案伺服器:
use std::path::{Path, PathBuf};
use rocket::fs::NamedFile;
#[get("public/<file..>")]
async fn files(file: PathBuf) -> Option<NamedFile> {
NamedFile::open(Path::new("static/").join(file)).await.ok()
}
也可以使用 FileServer,只需一行程式碼即可:
//引入FileServer結構體
use rocket::fs::FileServer;
//將/public作為URI字首,並將static/作為檔案路徑
rocket.mount("/public", FileServer::from("static/"))
在專案根目錄下建立一個名為static的資料夾,並將靜態檔案 example.txt 放在其中,透過以下uri訪問檔案:
http://localhost:8000/public/example.txt
在釋出專案時,可以將靜態資料夾放在與可執行檔案相同的目錄中,或者根據部署需求將其放在其他位置。
簡單WebAPI示例
下面使用Rocket實現一個簡單的WebAPI,這裡的示例只實現Post方法,不涉及JWT鑑權。
新增依賴
執行以下命令新增 serde 依賴:
cargo add serde --features "derive"
再執行一遍以下命令,開啟 json 功能標誌:
cargo add rocket --features "json"
實現介面
在 src/main.rs 檔案中實現以下程式碼:
#[macro_use] extern crate rocket;
use rocket::serde::{Deserialize, Serialize,json::Json};
#[derive(Debug, Deserialize)]
#[serde(crate = "rocket::serde")]
struct TaskRequest {
description: String,
complete: bool
}
#[derive(Debug, Serialize)]
#[serde(crate = "rocket::serde")]
struct TaskResponse {
description: String,
complete: bool
}
#[post("/todo", data = "<task>")]
fn my_function(task: Json<TaskRequest>) -> Json<TaskResponse> {
// 處理接收到的任務
println!("Received task: {:?}", task);
// 返回處理後的任務
Json(TaskResponse {
description: task.description.clone(),
complete: task.complete,
})
}
#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![my_function])
}
介面測試
使用 curl 測試一下介面,在cmd中執行以下命令:
curl -X POST -H "Content-Type: application/json" -d "{\"description\":\"Task 1\",\"complete\":true}" http://localhost:8000/todo
測試結果:
參考連結
- 簡單探索Rust Web開發
- rust基礎學習——web框架Rocket簡單入門
- Rocket 指導 v0.5 開始
- cmd輸出彩色字型(win10 cmd控制檯支援ANSI轉義序列)