spring-web插件

spring-web是基于axum实现的

crates.io Documentation

Axum是rust社区最优秀的Web框架之一,它是由tokio官方维护的一个基于hyper的子项目。Axum提供了web路由,声明式的HTTP请求解析,HTTP响应的序列化等功能,而且能够与tower生态中的中间件结合。

依赖

spring-web = { version = "<version>" }

可选的features: http2multipartws

配置项

[web]
binding = "172.20.10.4"  # 要绑定的网卡IP地址,默认0.0.0.0
port = 8000              # 要绑定的端口号,默认8080
connect_info = false     # 是否使用客户端连接信息,默认false
graceful = true          # 是否开启优雅停机, 默认false

# web中间件配置
[web.middlewares]
compression = { enable = true }  # 开启压缩中间件
catch_panic = { enable = true }  # 捕获handler产生的panic
logger = { enable = true, level = "info" }            # 开启日志中间件
limit_payload = { enable = true, body_limit = "5MB" } # 限制请求体大小
timeout_request = { enable = true, timeout = 60000 }  # 请求超时时间60s

# 跨域配置
cors = { enable = true, allow_origins = [
    "*.github.io",
], allow_headers = [
    "Authentication",
], allow_methods = [
    "GET",
    "POST",
], max_age = 60 }

# 静态资源配置
static = { enable = true, uri = "/static", path = "static", precompressed = true, fallback = "index.html" }

NOTE: 通过上面的middleware配置可以集成tower生态中提供的中间件。当然如果你对tower生态非常熟悉,也可以不启用这些middleware,通过编写代码自行配置。下面是相关的文档链接:

API接口

App实现了WebConfigurator特征,可以通过该特征指定路由配置:

1#[tokio::main]
2async fn main() {
3 App::new()
4 .add_plugin(SqlxPlugin)
5 .add_plugin(WebPlugin)
6 .add_router(router())
7 .run()
8 .await
9}
10
11fn router() -> Router {
12 Router::new().typed_route(hello_word)
13}
14
15#[get("/")]
16async fn hello_word() -> impl IntoResponse {
17 "hello word"
18}

你也可以使用auto_config宏来实现自动配置,这个过程宏会自动将被过程宏标记的路由注册进app中:

+#[auto_config(WebConfigurator)]
 #[tokio::main]
 async fn main() {
     App::new()
         .add_plugin(SqlxPlugin)
         .add_plugin(WebPlugin)
-        .add_router(router())
         .run()
         .await
}

属性宏

上面例子中的get是一个属性宏,spring-web提供了八个标准HTTP METHOD的过程宏:getpostpatchputdeleteheadtraceoptions

也可以使用route宏同时绑定多个method:

use spring_web::route;
use spring_web::axum::response::IntoResponse;

#[route("/test", method = "GET", method = "HEAD")]
async fn example() -> impl IntoResponse {
    "hello world"
}

除此之外,spring还支持一个handler绑定多个路由,这需要用到routes属性宏:

use spring_web::{routes, get, delete};
use spring_web::axum::response::IntoResponse;

#[routes]
#[get("/test")]
#[get("/test2")]
#[delete("/test")]
async fn example() -> impl IntoResponse {
    "hello world"
}

提取插件注册的Component

上面的例子中SqlxPlugin插件为我们自动注册了一个Sqlx连接池组件,我们可以使用Component从State中提取这个连接池,Component是一个axum的extractor

#[get("/version")]
async fn mysql_version(Component(pool): Component<ConnectPool>) -> Result<String> {
    let version = sqlx::query("select version() as version")
        .fetch_one(&pool)
        .await
        .context("sqlx query failed")?
        .get("version");
    Ok(version)
}

axum也提供了其他的extractor,这些都被reexport到了spring_web::extractor下。

读取配置

你可以用Config抽取toml中的配置。

#[derive(Debug, Configurable, Deserialize)]
#[config_prefix = "custom"]
struct CustomConfig {
    a: u32,
    b: bool,
}

#[get("/config")]
async fn use_toml_config(Config(conf): Config<CustomConfig>) -> impl IntoResponse {
    format!("a={}, b={}", conf.a, conf.b)
}

在你的配置文件中添加相应配置:

[custom]
a = 1
b = true

完整代码参考web-example

在Middleware中使用Component抽取注册的组件

你也可以在middleware中使用Extractor,注意需要遵循axum的规则。

use spring_web::{axum::{response::Response, middleware::Next}, extractor::{Request, Component}};
use spring_sqlx::ConnectPool;

async fn problem_middleware(Component(db): Component<ConnectPool>, request: Request, next: Next) -> Response {
    // do something
    let response = next.run(request).await;

    response
}

完整代码参考web-middleware-example