当前位置: 首页 > news >正文

Axum文档 ~ 2.路由

Struct Router(路由器结构体)

pub struct Router<S = ()> { /* private fields */ }

用于组合处理器(handler)和服务(service)的路由器类型。

Router<S> 表示一个 “缺少类型为 S 的状态才能处理请求” 的路由器。因此,只有 Router<()>(即不缺少任何状态的路由器)才能传递给 serve 方法。更多详情请参阅 Router::with_state 方法。

Implementations(实现)

Source

impl<S> Router<S>
whereS: Clone + Send + Sync + 'static,

创建路由

pub fn new() -> Self

创建一个新的 Router

除非你添加额外的路由,否则它会对所有请求返回 404 Not Found(未找到)响应。

关闭针对 0.7 版本路由匹配语法的兼容性检查

pub fn without_v07_checks(self) -> Self

关闭针对 0.7 版本路由匹配语法的兼容性检查。

这允许使用以冒号 : 或星号 * 开头的路径,否则这些路径是被禁止的。

示例

use axum::{routing::get,Router,
};let app = Router::<()>::new().without_v07_checks().route("/:colon", get(|| async {})).route("/*asterisk", get(|| async {}));// 我们的应用现在接受
// - GET /:colon
// - GET /*asterisk

如果不先调用此方法就添加此类路由,会触发 panic(崩溃)。

use axum::{routing::get,Router,
};// 这会触发 panic...
let app = Router::<()>::new().route("/:colon", get(|| async {}));

Merging(合并)

当两个路由器合并时,如果两个路由器均已关闭 v0.7 版本检查,则合并后路由器上的路由注册也会禁用该检查。

Nesting(嵌套)

每个路由器都需要显式关闭该检查。嵌套一个已启用或已禁用该检查的路由器,对外部路由器没有影响。

添加另一条路由

pub fn route(self, path: &str, method_router: MethodRouter<S>) -> Self

向路由器中添加另一条路由。

path 是由 / 分隔的路径段组成的字符串。每个路径段可以是静态段、捕获段(capture)或通配符段(wildcard)。

如果路径与 path 匹配,method_router 是应接收请求的 MethodRouter。通常,method_router 是一个被包裹在 get 等方法路由器中的处理器(handler)。有关处理器的更多详情,请参阅 handler 相关文档。

Static paths(静态路径)

示例:

/

/foo

/users/123

如果传入的请求与路径完全匹配,对应的服务(service)将被调用。

Captures(捕获段)

路径中可以包含 / {key} 这样的路径段,它能匹配任意单个路径段,并会将捕获到的值存储在 key 对应的位置。捕获到的值可以是空字符串,但无效路径 // 除外。

示例:

/ {key}

/users/{id}

/users/{id}/tweets

可以使用 Path 提取捕获到的值。有关更多详情,请参阅其文档。

无法创建仅匹配特定类型(如数字或正则表达式)的路径段。你必须在处理器中手动处理这类需求。

可以使用 MatchedPath 提取匹配到的路径,而非实际请求路径。

Wildcards(通配符段)

路径可以以 / {*key} 结尾,它能匹配所有后续路径段,并会将这些路径段存储在 key 对应的位置。

示例:

/ {*key}

/assets/{*path}

/{id}/{repo}/{*tree}

注意,/{*key} 不匹配空路径段。因此:

/{*key} 不匹配 /,但匹配 /a/a/ 等。

/x/{*key} 不匹配 /x 或 /x/,但匹配 /x/a/x/a/ 等。

通配符捕获到的值也可以使用 Path 提取:

use axum::{Router,routing::get,extract::Path,
};let app: Router = Router::new().route("/{*key}", get(handler));async fn handler(Path(path): Path<String>) -> String {path
}

注意,结果中不包含开头的斜杠 /,例如,对于路由 /foo/{*rest} 和请求路径 /foo/bar/bazrest 的值将是 bar/baz

Accepting multiple methods(接受多种请求方法)

若要为同一条路由接受多种请求方法,你可以一次性添加所有处理器:

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));

More examples(更多示例)

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 会拥有优先级。

如果 path 为空,也会触发 panic

添加另一条路由,调用 Service(服务)

pub fn route_service<T>(self, path: &str, service: T) -> Self
whereT: Service<Request, Error = Infallible> + Clone + Send + Sync + 'static,T::Response: IntoResponse,T::Future: Send + 'static,

向路由器中添加另一条路由,该路由会调用一个 Service(服务)。

示例

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(// 所有对 `/` 的请求都会指向一个服务"/",// 响应体不是 `axum::body::BoxBody` 的服务// 可以被包裹在 `axum::routing::any_service`(或其他路由过滤器之一)中// 以实现响应体的映射any_service(service_fn(|_: Request| async {let res = Response::new(Body::from("Hi from `GET /`"));Ok::<_, Infallible>(res)}))).route_service("/foo",// 此服务的响应体是 `axum::body::BoxBody`,因此// 可以直接将路由指向它。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(// GET 请求 `/static/Cargo.toml` 会指向 tower-http 中的一个服务"/static/Cargo.toml",ServeFile::new("Cargo.toml"),);

以这种方式将路由指向任意服务,在背压(backpressure)处理(即 Service::poll_ready 方法)方面会存在复杂性。有关更多详情,请参阅 “Routing to services and backpressure” 模块。

Panics(恐慌场景)

会因与 Router::route 相同的原因触发 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

在某个路径下嵌套(nest)一个 Router

这允许你将应用拆分为多个较小的模块,并将它们组合在一起。

示例

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);// 我们的应用现在接受
// - GET /api/users/{id}
// - POST /api/teams

URI 的变化

注意,嵌套路由无法获取原始请求 URI,而是会将匹配到的前缀路径移除。这对于静态文件服务等服务的正常工作是必需的。如果需要获取原始请求 URI,请使用 OriginalUri

来自外部路由的捕获值

当将 nest 与动态路由一起使用时需注意,嵌套路由也会捕获外部路由中的路径参数:

use axum::{extract::Path,routing::get,Router,
};
use std::collections::HashMap;async fn users_get(Path(params): Path<HashMap<String, String>>) {// 尽管 `users_api` 仅显式捕获了 `id`,但 `version` 和 `id` 均会被捕获。let version = params.get("version");let id = params.get("id");
}let users_api = Router::new().route("/users/{id}", get(users_get));let app = Router::new().nest("/{version}/api", users_api);

与通配符路由的区别

嵌套路由与通配符路由类似。不同之处在于,通配符路由仍能获取完整 URI,而嵌套路由会移除前缀路径:

use axum::{routing::get, http::Uri, Router};let nested_router = Router::new().route("/", get(|uri: Uri| async {// `uri` 将**不**包含 `/bar`}));let app = Router::new().route("/foo/{*rest}", get(|uri: Uri| async {// `uri` 将包含 `/foo`})).nest("/bar", nested_router);

此外,通配符路由 /foo/*rest 不会匹配 /foo 或 /foo/ 路径,而在 /foo 路径下的嵌套路由器会匹配 /foo(但不匹配 /foo/),在 /foo/ 路径下的嵌套路由器会匹配 /foo/(但不匹配 /foo)。

Fallbacks(兜底处理器)

如果嵌套路由器没有自己的兜底处理器(fallback),则会继承外部路由器的兜底处理器:

use axum::{routing::get, http::StatusCode, handler::Handler, Router};async fn fallback() -> (StatusCode, &'static str) {(StatusCode::NOT_FOUND, "Not Found")
}let api_routes = Router::new().route("/users", get(|| async {}));let app = Router::new().nest("/api", api_routes).fallback(fallback);

在此处,像 GET /api/not-found 这样的请求会进入 api_routes,但由于 api_routes 中没有匹配的路由,也没有自己的兜底处理器,因此会调用外部路由器的兜底处理器(即 fallback 函数)。

如果嵌套路由器有自己的兜底处理器,则不会继承外部路由器的兜底处理器:

use axum::{routing::get,http::StatusCode,handler::Handler,Json,Router,
};async fn fallback() -> (StatusCode, &'static str) {(StatusCode::NOT_FOUND, "Not Found")
}async fn api_fallback() -> (StatusCode, Json<serde_json::Value>) {(StatusCode::NOT_FOUND,Json(serde_json::json!({ "status": "Not Found" })),)
}let api_routes = Router::new().route("/users", get(|| async {})).fallback(api_fallback);let app = Router::new().nest("/api", api_routes).fallback(fallback);

在此处,像 GET /api/not-found 这样的请求会指向 api_fallback

Nesting routers with state(嵌套带状态的路由器)

当使用此方法组合多个 Router 时,每个 Router 必须拥有相同类型的状态(state)。如果你的路由器类型不同,可以使用 Router::with_state 方法提供状态,使类型匹配:

use axum::{Router,routing::get,extract::State,
};#[derive(Clone)]
struct InnerState {}#[derive(Clone)]
struct OuterState {}async fn inner_handler(state: State<InnerState>) {}let inner_router = Router::new().route("/bar", get(inner_handler)).with_state(InnerState {});async fn outer_handler(state: State<OuterState>) {}let app = Router::new().route("/", get(outer_handler)).nest("/foo", inner_router).with_state(OuterState {});

注意,内部路由器仍会继承外部路由器的回退处理器。

Panics(崩溃场景)

  • 如果路由与另一条路由重叠。有关更多详情,请参阅 Router::route
  • 如果路径中包含通配符(*)。
  • 如果 path 为空。
pub fn nest_service<T>(self, path: &str, service: T) -> Self
whereT: Service<Request, Error = Infallible> + Clone + Send + Sync + 'static,T::Response: IntoResponse,T::Future: Send + 'static,

与 nest 类似,但接受任意 Service(服务)。

pub fn merge<R>(self, other: R) -> Self
whereR: Into<Router<S>>,

将两个路由器的路径和回退处理器合并为一个 Router

这对于将应用拆分为多个较小的模块并将它们组合成一个整体非常有用。

use axum::{routing::get,Router,
};// 单独定义一些路由
let user_routes = Router::new().route("/users", get(users_list)).route("/users/{id}", get(users_show));let team_routes = Router::new().route("/teams", get(teams_list));// 将它们组合成一个路由器
let app = Router::new().merge(user_routes).merge(team_routes);// 也可以写成 `user_routes.merge(team_routes)`// 我们的应用现在接受
// - GET /users
// - GET /users/{id}
// - GET /teams

Merging routers with state(合并带状态的路由器)

当使用此方法组合多个 Router 时,每个 Router 必须拥有相同类型的状态(state)。如果你的路由器类型不同,可以使用 Router::with_state 方法提供状态


文章转载自:

http://SKYmAb2U.Ldqzz.cn
http://hJWx4u4A.Ldqzz.cn
http://xrFuJsZE.Ldqzz.cn
http://5FQnQfqh.Ldqzz.cn
http://G9wXNNhz.Ldqzz.cn
http://aQPX5VWS.Ldqzz.cn
http://6De8DSGs.Ldqzz.cn
http://VVclbeov.Ldqzz.cn
http://ECJEzDJH.Ldqzz.cn
http://HhaxDmEc.Ldqzz.cn
http://uo34aVHR.Ldqzz.cn
http://H5iKW3Lc.Ldqzz.cn
http://iEtxdcAw.Ldqzz.cn
http://aGbB2yZ1.Ldqzz.cn
http://JsVkaevp.Ldqzz.cn
http://4cplIJ0t.Ldqzz.cn
http://jAjcyMw5.Ldqzz.cn
http://JKyNV7c9.Ldqzz.cn
http://pWnR3z7r.Ldqzz.cn
http://TT2Ud2Cl.Ldqzz.cn
http://ldbriRHU.Ldqzz.cn
http://7eO000Jw.Ldqzz.cn
http://9nvjS83C.Ldqzz.cn
http://mbOw95vv.Ldqzz.cn
http://pHmDUX09.Ldqzz.cn
http://HRrxgobD.Ldqzz.cn
http://borNy1IP.Ldqzz.cn
http://McZQGS6A.Ldqzz.cn
http://sO0FEOFP.Ldqzz.cn
http://7qcJ6OTJ.Ldqzz.cn
http://www.dtcms.com/a/373106.html

相关文章:

  • 【C++】IO库
  • 常见的显示器接口技术
  • 如何在本地机器上使用LLM构建知识图谱(一)
  • 论文阅读:ACL 2023 MPCHAT: Towards Multimodal Persona-Grounded Conversation
  • Java全栈开发工程师的实战面试:从基础到微服务
  • 向量回归策略
  • 【数据库】时序数据库科学选型,以IoTDB构筑大数据时代的时序数据底座
  • MAUI劝退:安卓实体机测试
  • Day8 C++
  • 在线教程 | VibeVoice-1.5B独创双Tokenizer架构实现一次性生成90分钟4人对话语音,重新定义TTS技术边界
  • 《练手:ipv4地址计算和Telnet 远程设备管理配置实验文档》
  • [论文阅读] 人工智能 + 软件工程 | TDD痛点破解:LLM自动生成测试骨架靠谱吗?静态分析+专家评审给出答案
  • 【计算机网络 | 第10篇】信道复用技术
  • Pytest+requests进行接口自动化测试1.0(基础知识 + 测试用例 + request库)
  • 使用 OpenLayers + 高德瓦片源实现旅游足迹地图
  • 2025年体制内职业发展相关资格认证参考指南
  • window显示驱动开发—监视筛选器驱动程序(三)
  • 计算机网络:数据链路层--数据链路层基本功能
  • 第二课、熟悉Cocos Creator 编辑器界面
  • [Wit]CnOCR模型训练全流程简化记录(包括排除BUG)
  • JavaEE 进阶第四期:开启前端入门之旅(四)
  • TFS-2004《Input Selection for Nonlinear Regression Models》
  • esp下载器使用流程
  • 3dtiles 加载问题
  • 3D地球可视化教程 - 第1篇:基础地球渲染系统
  • 单片机开发
  • LLMs之REFRAG:《REFRAG: Rethinking RAG based Decoding》的翻译与解读
  • MATLAB的数值计算(二)线性方程求解
  • Java基础(十一):关键字final详解
  • Java全栈开发面试实录:从基础到微服务的实战经验分享