當初,作為初學者,我發現自己很笨拙,無法學會使用 actix-web、Rocket 等現有框架。當我想把以前用 Go 寫的 Web 服務改用 Rust 實現時,乍看之下,似乎每個框架都比 Go 的現有框架複雜。Rust 的學習曲線已經夠陡峭了,何必還要把 Web 框架搞得那麼複雜?
當 Tokio 推出 Axum 框架時,我開心地以為以後不必再維護自己的 Web 框架了。然而事實是,Axum 看似簡單,實際使用時卻需要大量類型體操和泛型定義,必須對 Rust 語言有深刻理解並寫出大量晦澀難懂的模板代碼,才能完成一個簡單的中間件。
因此我決定繼續維護這個特別(順手、功能豐富且適合初學者)的 Web 框架。
Salvo 雖然簡單,但功能足夠全面強大,基本可以視為 Rust 界最強的框架。然而,如此強大的系統,學習和使用卻非常簡單,絕對不會讓你感到任何「揮刀自宮」的痛苦。
它適合剛開始學習 Rust 的初學者。CRUD 是極其平常且常用的功能,如果用 Salvo 做類似工作,你會發現它和你用過的其他語言 Web 框架一樣簡單(例如:Express、Koa、gin、flask...),甚至在某些方面更抽象簡潔;
它適合希望將 Rust 用於生產環境,提供穩健快速伺服器的人。雖然 Salvo 尚未發布 1.0 版本,但其核心功能已經過幾年迭代,足夠穩定且問題修復及時;
它適合毛髮已不再茂密但仍每天不停掉髮的你。
許多底層實現 Hyper 都已提供,因此一般需求基於 Hyper 實現應該沒錯。Salvo 也是如此。核心功能是一個強大且靈活的路由系統,以及許多常用功能,如 Acme、OpenAPI、JWT Auth 等。
Salvo 統一了 Handler 和 Middleware。Middleware 就是 Handler,通過路由的 hoop 添加到 Router 上。本質上,Middleware 和 Handler 都是處理 Request 請求,並可能向 Response 寫入數據。而 Handler 接收的參數是 Request、Depot、Response 三個,其中 Depot 用於儲存請求處理過程中的臨時數據。
為方便書寫,用不到時可省略某些參數,也可無視參數傳入順序。
此外,路由系統提供的 API 極其簡單,但功能強大。正常使用需求下,基本上只需關注 Router 一個類型即可。 另外,如果結構體實現了相關 trait,Salvo 可以自動生成 OpenAPI 文檔及提取參數,自動處理不同錯誤並返回友好提示。這使得編寫 handler 就像編寫普通函數一樣簡單直觀。後續教程會詳細講解這些功能,以下是範例:
此範例中,JsonBody<CreateOrUpdateMessageLog>
會自動從請求體解析 JSON 數據並轉換為 CreateOrUpdateMessageLog
類型(也支援多數據源、嵌套類型),同時 #[endpoint]
宏會自動為此接口生成 OpenAPI 文檔,簡化參數提取和錯誤處理的代碼。
我認為路由系統與其他框架不同。Router 可以寫成平面,也可以寫成樹狀。這裡區分業務邏輯樹與訪問目錄樹。業務邏輯樹根據業務需求劃分 router 結構,形成 router 樹,它不一定與訪問目錄樹一致。
通常我們這樣寫路由:
查看文章和文章列表通常不需用戶登錄,但創建、編輯、刪除文章等需要登錄認證權限。Salvo 支援嵌套路由系統,可很好滿足這種需求。我們可將不需登錄的路由寫在一起:
然後將需要登錄的路由寫在一起,並使用相應中間件驗證用戶是否登錄:
雖然這兩個路由都有相同的 path("articles")
,但它們仍可同時添加到同一個父路由,因此最終路由長這樣:
{id}
匹配路徑中的一個片段。通常文章 id
只是數字,這時我們可用正則表達式限制 id
的匹配規則:r"{id:/\d+/}"
。