天天看點

【大家的項目】Salvo - 一個簡單的 Web 後端架構

為什麼要寫這個架構

因為我笨,無法學會使用 actix-web 等現存的架構。當我想把以前的 go 的 web 服務使用 rust 實作時,一眼看去,似乎每個架構都比 go 裡存在架構複雜, 本來 Rust 的學習曲線就夠陡峭的了, 又何苦把 Web 架構整得那麼複雜?

如何做到足夠簡單

很多底層的實作 Hyper 都已經實作,是以,一般需求,基于 Hyper 實作應該沒有錯。Salvo 也是一樣。核心功能是提供還用簡單的API,以及一個功能強大并且靈活的路由系統。

Salvo 裡統一了 Handler 和 Middleware. Middleware 就是 Handler. 通過路由的 before 或者 after 添加到 Router 上。本質上, Middleware 和 Handler 都是處理 Request 請求,并且可能向 Response 寫入資料。而 Handler 接收的參數是 Request, Depot, Response 三個, 其中 Depot 用于存儲請求處理過程中的臨時資料. 為友善書寫, 在用不着的情況下可以省略掉某些參數.

use Salvo::prelude::*;

#[fn_handler]

async fn hello_world(_req: &mut Request, _depot: &mut Depot, res: &mut Response) {

res.render_plain_text("Hello World");

}

#[fn_handler]

async fn hello_world2(res: &mut Response) {

res.render_plain_text("Hello World");

}

另外路由系統提供的 API 也是極其簡單的, 但是, 功能卻是強大的. 正常使用需求下, 基本上就是隻關注 Router 一個類型即可.

路由系統

我自己感覺路由系統是跟其他的架構不太一樣的. Router 可以寫平,也可以寫成樹狀。這裡區業務邏輯樹與通路目錄樹。業務邏輯樹是根據業務邏輯需求,劃分 router 結構,形成 router 樹,它不一定與通路目錄樹一緻。

正常情況下我們是這樣寫路由的:

Router::new().path("articles").get(list_articles).post(create_article);

Router::new()

.path("articles/<id>")

.get(show_article)

.patch(edit_article)

.delete(delete_article);

往往檢視文章和文章清單是不需要使用者登入的, 但是建立, 編輯, 删除文章等需要使用者登入認證權限才可以. Salvo 中支援嵌套的路由系統可以很好地滿足這種需求. 我們可以把不需要使用者登入的路由寫到一起:

Router::new()

.path("articles")

.get(list_articles)

.push(Router::new().path("<id>").get(show_article));

然後把需要使用者登入的路由寫到一起, 并且使用相應的中間件驗證使用者是否登入:

Router::new()

.path("articles")

.before(auth_check)

.post(list_articles)

.push(Router::new().path("<id>").patch(edit_article).delete(delete_article));

雖然這兩個路由都有這同樣的 ​

​path("articles")​

​, 然而它們依然可以被同時添加到同一個父路由, 是以最後的路由長成了這個樣子:

Router::new()

.push(

Router::new()

.path("articles")

.get(list_articles)

.push(Router::new().path("<id>").get(show_article)),

)

.push(

Router::new()

.path("articles")

.before(auth_check)

.post(list_articles)

.push(Router::new().path("<id>").patch(edit_article).delete(delete_article)),

);

​<id>​

​​比對了路徑中的一個片段, 正常情況下文章的 ​

​id​

​​ 隻是一個數字, 這是我們可以使用正規表達式限制 ​

​id​

​​ 的比對規則, ​

​r"<id:/\d+/>"​

​.

更多資訊可以檢視網站 https://salvo.rs

  • 在 issue 中送出功能需求和 bug report;
  • 在 issues 或者 require feedback 下留下自己的意見;
  • 通過 pull requests 送出代碼;
  • 在部落格或者技術平台發表 Salvo 相關的技術文章。