目录
axum路由器
axum::Router结构体
pub struct Router<S = ()> { /* private fields */}
用于组合处理程序和服务的路由器类型。
实现
impl<S> Router<S>
where
S: Clone + Send + Sync + 'static,
新建路由器
pub fn new() -> Self
创建一个新的路由器,除非您添加额外的路由,否则将对所有请求响应404未找到。
添加另一个路由到路 由器
pub fn route(self, path: &str, method_router: MethodRouter<S>) -> Self
path: 是由/分割的路径段字符串。每个段可能是静态的、捕获的或者是通配符。method_router: 是一个MethodRouter,它将请求方法映射到处理程序。method_router通常会是类似于get的方法路由器中的处理程序。
静态路径
例如:
//foo/foo/bar
如果传入的请求路径完全匹配,则将调用相应的服务。
捕获
例如:
/:key/foo/:key/users/:id/tweets
路径可以包含类似于/:key的段,它匹配任何单个段,并将存储在key处捕获的值。
捕获的值可以是零长度,除了无效路径//
捕获可以使用Path进行提取。
MatchedPath可以用于提取匹配路径,而不是实际路径。
通配符
路径可以以/*key结尾,匹配所有段并捕获的段存储在key中。
例如:
/*key/users/*path/:id/:repo/*tree
请注意,/*key 不匹配空段。因此:
/*key不匹配/,但匹配/a,/a/等。/x/*key不匹配/x或/x/,但匹配/x/a,/x/a/等。
还可以使用 Path 来提取通配符捕获。
请注意,不包括前导斜杠,即对于路由 /foo/*rest 和路径 /foo/bar/baz,
rest 的值将是 bar/baz。
接受多种方法
要接受同一路由的多个方法,您可以同时添加所有处理程序。
use axum::{Router, routing::{get, delete}, extract::Path};
let app = Router::new().route(
"/",
get(get_root).post(post_root).delete(delete_root),
);
async fn get_root() {}
async fn post_root() {}
async fn delete_root() {}
或者你也可以一一添加:
let app = Router::new()
.route("/", get(get_root))
.route("/", post(post_root))
.route("/", delete(delete_root));
更多例子
use axum::{Router, routing::{get, delete}, extract::Path};
let app = Router::new()
.route("/", get(root))
.route("/users", get(list_users).post(create_user))
.route("/users/:id", get(show_user))
.route("/api/:version/users/:id/action", delete(do_users_action))
.route("/assets/*path", get(serve_asset));
async fn root() {}
async fn list_users() {}
async fn create_user() {}
async fn show_user(Path(id): Path<u64>) {}
async fn do_users_action(Path((version, id)): Path<(String, u64)>) {}
async fn serve_asset(Path(path): Path<String>) {}
Panics
如果路径与另一个路由重叠,则会发生panic
use axum::{routing::get, Router};
let app = Router::new()
.route("/", get(|| async {}))
.route("/", get(|| async {}));
静态路由 /foo 和动态路由 /:key 不被视为重叠,并且 /foo 将优先。
如果路径为空,也会引发 panic。
路由服务
添加另一个路由到路由器调用一个服务
pub fn route_service<T>(self, path: &str, service: T) -> Self
where
T: Service<Request, Error=Infallible> + Clone + Send + 'static,
T::Response: IntoResponse,
T::Future: Send + 'static,
示例:
use axum::{
Router,
body::Body,
routing::{any_service, get_service},
extract::Request,
http::StatusCode,
error_handling::HandleErrorLayer,
};
use tower_http::services::ServeFile;
use http::Response;
use std::{convert::Infallible, io};
use tower::service_fn;
let app = Router::new()
.route(
"/",
any_service(service_fn(|_: Request| async {
let res = Response::new(Body::from("Hi from `GET /`"));
}))
)
.route_service(
"/foo",
service_fn(|req: Request| async move {
let body = Body::from(format!("Hi from `{}` /foo", req.method()))
let res = Response::new(body);
Ok::<_, Infallible>(res)
})
)
.route_service(
"/static/Cargo.toml",
ServeFile::new("Cargo.toml"),
);
以这种方式路由到任意服务会对背压(Service::poll_ready)产生复杂性。
有关更多详细信息,请参阅服务路由和背压模块。
由于相同的原因而出现panic,或者尝试将路由到Router时也会发生panic。
use axum::{routing::get, Router};
let app = Router::new().route_service(
"/",
Router::new().route("/foo", get(|| async {})),
);
使用Router::nest替换
在某个路径上嵌套一个路由器。
这样可以将应用程序分解成更小的部分,并将它们组合在一起。
pub fn nest(self, path: &str, router: Router<S>) -> Self
示例:
use axum::{
routing::{get, post},
Router,
};
let user_routes = Router::new().route("/:id", get(|| async {}));
let team_routes = Router::new().route("/", post(|| async {}));
let api_routes = Router::new()
.nest("/users", user_routes)
.nest("/teams", team_routes);
let app = Router::new().nest("/api", api_routes);
// Our app now accepts
// - GET /api/users/:id
// - POST /api/teams
URI如何变化
请注意,嵌套路由将无法看到原始请求URI,而是会剥去匹配的前缀。
这对于像静态文件服务之类的服务工作是必要的。
如果需要原始请求URI,请使·OriginalUri。