axum是一个rust的现代web框架,具有API简单,与tokio异步生态兼容性强等优点。

要使用Axum,你至少需要现在项目依赖中添加一下几个依赖:

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

然后你可以使用以下Axum代码启动一个HTTP服务器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

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 our app with hyper, listening globally on port 3000
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}

Handler

Axum处理请求的异步函数,接受一个extractor,用于从HTTP请求中提取参数;返回一个实现了IntoResponse Trait的泛型,用于构建HTTP回应。

Extractor

任何实现了 FromRequest 或者 FromRequestParts trait的结构体都可以作为一个 Extractor,从请求中提取想要的参数,这两个trait唯一的不同是 FromRequest 会消耗请求体,而 FromRequestParts 不会。

以下是 FromRequest trait:

1
2
3
4
5
6
7
8
9
10
11
pub trait FromRequest<S, M = private::ViaRequest>: Sized {
/// If the extractor fails it'll use this "rejection" type. A rejection is
/// a kind of error that can be converted into a response.
type Rejection: IntoResponse;

/// Perform the extraction.
fn from_request(
req: Request,
state: &S,
) -> impl Future<Output = Result<Self, Self::Rejection>> + Send;
}

而以下是 FromRequestParts trait:

1
2
3
4
5
6
7
8
9
10
11
12
pub trait FromRequestParts<S>: Sized {
/// If the extractor fails it'll use this "rejection" type. A rejection is
/// a kind of error that can be converted into a response.
type Rejection: IntoResponse;

/// Perform the extraction.
fn from_request_parts(
parts: &mut Parts,
state: &S,
) -> impl Future<Output = Result<Self, Self::Rejection>> + Send;
}

Axum 给我们提前准备了多个常用的Extractor,例如:

Extractor 作用
Path(user_id): Path 用于从请求路径中提取参数
Query(params): Query<HashMap<String, String>> 用于从请求参数中提取参数
Json(payload): Json<serde_json::Value> 用于提取请求体中的JSON参数

IntoResponse

任何实现了 IntoResponse trait 的结构体都可以作为一个 handler 的返回参数,用于构建 HTTP Response。IntoResponse trait 如下:

1
2
3
4
5
6
7
pub type Response<T = Body> = http::Response<T>;

pub trait IntoResponse {
/// Create a response.
#[must_use]
fn into_response(self) -> Response;
}

这里的 Response 就是 http 库中的 Resposne。使用Axum的时候通常不要求我们自己实现这个trait,因为Axum已经提前给大多数我们用得到的类型实现了这个trait,例如:

  • http::StatusCode, (), Infalliable, Body
  • Result<T,E> where T: IntoResponse, E: IntoResponse
  • Response where B; Body + Send
  • http::response::Parts, http::HeaderMap, http::Extensions
  • 'static str, String, Box, Cow<'static, str>
  • 'static [u8], 'static [u8; N], Vec, Box<[u8]>, Cow<'static, [u8]>
  • (StatusCode, T) where T: IntoResponse
  • bytes::Bytes, bytes::BytesMut, bytes::Chain, bytes::BytesChainBody
  • [(K, V); N] where K: TryInto, K::Error: fmt::Display,
    V: TryInto, V::Error: fmt::Display
  • (http::response::Parts, R) where R: IntoResponse
  • (http::response::Response<()>, R) where R: IntoResponse
  • (R,) where R: IntoResponse

并且给这些类型的组合起来的元组也实现了这个trait。