土猛的员外

axum中文简述

字数统计: 1.8k阅读时长: 8 min
2023/03/01

以下文档基于axum Version 0.6.17

axum是一个专注于极简高效和模块化的web应用程序框架。

高级特性

  • 使用无宏API将请求路由到处理程序。
  • 使用提取器声明性地解析请求。
  • 简单和可预测的错误处理模型。
  • 用最少的样板文件生成响应。
  • 充分利用中间件、服务和实用程序的towertower-http生态系统。

最后一点是“axum”区别于其他框架的地方。axum没有自己的中间件系统,而是使用tower::Service。这意味着“axum”可以免费获得超时、跟踪、压缩、授权等。它还允许您与使用‘ hyper ‘‘ tonic ‘编写的应用程序共享中间件。

兼容性

axum是为配合tokiohyper设计的,运行时层和传输层的独立性不是目标,至少目前不是。

示例

axum的 “Hello, World!” :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use axum::{
routing::get,
Router,
};

#[tokio::main]
async fn main() {
// build our application with a single route
let app = Router::new().route("/", get(|| async { "Hello, World!" }));

// run it with hyper on localhost:3000
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}

注意使用#[tokio::main]需要启用tokio的macrosrt-multi-thread功能,或者只启用full来启用所有功能(cargo add tokio—features macros,rt-multi-thread)。

路由(ROUTING)

Router 用于设置哪些路径指向哪些服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
use axum::{Router, routing::get};

// our router
let app = Router::new()
.route("/", get(root))
.route("/foo", get(get_foo).post(post_foo))
.route("/foo/bar", get(foo_bar));

// which calls one of these handlers
async fn root() {}
async fn get_foo() {}
async fn post_foo() {}
async fn foo_bar() {}

细节可以查看 Router 

处理器(Handlers)

在axum中,处理器(“handler”)是一个异步函数,它接受零个或多个“extractors”作为参数,并返回可以转换为response的内容

处理器是应用程序逻辑存在的地方,而axum应用程序是通过处理器之间的路由构建的。

请参见‘ handler ‘了解处理程序的更多详细信息。

提取器(Extractors)

提取器是一种实现FromRequestFromRequestParts的类型。提取器是您如何分离传入请求以获得处理程序所需的部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
use axum::extract::{Path, Query, Json};
use std::collections::HashMap;

// `Path` gives you the path parameters and deserializes them.
async fn path(Path(user_id): Path<u32>) {}

// `Query` gives you the query parameters and deserializes them.
async fn query(Query(params): Query<HashMap<String, String>>) {}

// Buffer the request body and deserialize it as JSON into a
// `serde_json::Value`. `Json` supports any type that implements
// `serde::Deserialize`.
async fn json(Json(payload): Json<serde_json::Value>) {}

更多细节可以参看 extract .

响应(Responses)

任何实现IntoResponse的东西都可以从处理器返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use axum::{
body::Body,
routing::get,
response::Json,
Router,
};
use serde_json::{Value, json};

// `&'static str` becomes a `200 OK` with `content-type: text/plain; charset=utf-8`
async fn plain_text() -> &'static str {
"foo"
}

// `Json` gives a content-type of `application/json` and works with any type
// that implements `serde::Serialize`
async fn json() -> Json<Value> {
Json(json!({ "data": 42 }))
}

let app = Router::new()
.route("/plain_text", get(plain_text))
.route("/json", get(json));

更多细节参看 response 。

错误处理(Error handling)

axum旨在提供一个简单且可预测的错误处理模型,这意味着将错误转换为响应很简单,并且可以保证所有错误都得到处理。

参见error_handling了解更多关于axum错误处理模型以及如何优雅地处理错误的详细信息。

中间件(Middleware)

为axum编写中间件有几种不同的方法。详见‘中间件’

与处理器共享状态(Sharing state with handlers)

在处理程序之间共享某些状态是很常见的。例如,可能需要共享到其他服务的数据库连接或客户端池。

最常见的三种方法是:

  • 使用State提取器
  • 使用请求扩展
  • 使用闭包捕获

使用 State extractor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use axum::{
extract::State,
routing::get,
Router,
};
use std::sync::Arc;

struct AppState {
// ...
}

let shared_state = Arc::new(AppState { /* ... */ });

let app = Router::new()
.route("/", get(handler))
.with_state(shared_state);

async fn handler(
State(state): State<Arc<AppState>>,
) {
// ...
}

如果可能的话,您应该更喜欢使用State,因为它更类型安全。缺点是它不如Request extensions 具有动态性。

有关访问状态的更多细节,请参见State

使用 request extensions

在处理器中提取状态的另一种方法是使用Extension 作为层和提取器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use axum::{
extract::Extension,
routing::get,
Router,
};
use std::sync::Arc;

struct AppState {
// ...
}

let shared_state = Arc::new(AppState { /* ... */ });

let app = Router::new()
.route("/", get(handler))
.layer(Extension(shared_state));

async fn handler(
Extension(state): Extension<Arc<AppState>>,
) {
// ...
}

这种方法的缺点是,如果您尝试提取一个不存在的扩展,可能是因为您忘记添加中间件,或者因为您提取了错误的类型,那么您将得到运行时错误(特别是500 Internal Server Error 响应)。

使用闭包捕获(closure captures)

State也可以使用闭包捕获直接传递给处理器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
use axum::{
Json,
extract::{Extension, Path},
routing::{get, post},
Router,
};
use std::sync::Arc;
use serde::Deserialize;

struct AppState {
// ...
}

let shared_state = Arc::new(AppState { /* ... */ });

let app = Router::new()
.route(
"/users",
post({
let shared_state = Arc::clone(&shared_state);
move |body| create_user(body, shared_state)
}),
)
.route(
"/users/:id",
get({
let shared_state = Arc::clone(&shared_state);
move |path| get_user(path, shared_state)
}),
);

async fn get_user(Path(user_id): Path<String>, state: Arc<AppState>) {
// ...
}

async fn create_user(Json(payload): Json<CreateUserPayload>, state: Arc<AppState>) {
// ...
}

#[derive(Deserialize)]
struct CreateUserPayload {
// ...
}

这种方法的缺点是它比使用‘ State ‘或extensions更冗长。

为axum构建集成

想要为FromRequestFromRequestParts,或IntoResponse提供实现的lib作者应该依赖于axum-corecrate,而不是axum axum-core 包含核心类型和特征,不太可能收到破坏性更改。

需要的依赖

为了使用axum,你还需要引入一些依赖项

1
2
3
4
5
[dependencies]
axum = "<latest-version>"
hyper = { version = "<latest-version>", features = ["full"] }
tokio = { version = "<latest-version>", features = ["full"] }
tower = "<latest-version>"

hyper和tokio的“full”功能并不是必须的,但这是最简单的入门方法。

注意hyper::Server 是由axum重新导出的,所以只需要这个,那么你不必显式地依赖hyper。

Tower也不是严格必要的,但有助于测试。请参阅回购中的测试示例,以了解有关测试axum应用程序的更多信息。

更多示例

axum repo包含许多示例,展示了如何将所有部分组合在一起。

功能标志

axum使用一组feature flags来减少已编译和可选依赖项的数量。

可选特性包括:

Name Description Default?
headers 通过TypedHeader使得提取已输入标题成为可能 No
http1 启用 Hyper 的 HTTP1 功能 Yes
http2 启用 Hyper 的 HTTP2 功能 No
json 启用Json类型和一些类似的便利功能。 Yes
macros 启用可选实用宏 No
matched-path 使得能够捕获每个请求的路由路径和MatchedPath提取器。 Yes
multipart 使用Multipart使得解析multipart/form-data请求成为可能 No
original-uri 使得能够捕获每个请求的原始URI和OriginalUri提取器。 Yes
tokio 使得Tokio成为依赖项,并提供axum::ServerSSEextract::connect_info类型。 Yes
tower-log Enables tower’s log feature Yes
tracing 记录内置提取器的拒绝。 No
ws 通过extract::ws启用WebSockets支持 No
form 启用Form提取器 Yes
query 启用Query提取器 Yes


关注我的微信公众号,可收到实时更新通知

公众号:土猛的员外

原文作者:yuanwai

原文链接:https://www.luxiangdong.com/2023/03/01/axum1/

发表日期:March 1st 2023, 3:15:20 pm

更新日期:May 4th 2023, 1:40:39 pm

版权声明:

CATALOG
  1. 1. 高级特性
  2. 2. 兼容性
  3. 3. 示例
  4. 4. 路由(ROUTING)
  5. 5. 处理器(Handlers)
  6. 6. 提取器(Extractors)
  7. 7. 响应(Responses)
  8. 8. 错误处理(Error handling)
  9. 9. 中间件(Middleware)
  10. 10. 与处理器共享状态(Sharing state with handlers)
    1. 10.1. 使用 State extractor
    2. 10.2. 使用 request extensions
    3. 10.3. 使用闭包捕获(closure captures)
  11. 11. 为axum构建集成
  12. 12. 需要的依赖
  13. 13. 更多示例
  14. 14. 功能标志