尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

axum 路由详解:Router::route 的静态路径、捕获段与通配符匹配规则

axum 路由详解:Router::route 的静态路径、捕获段与通配符匹配规则 axum 路由详解Router::route 的静态路径、捕获段与通配符匹配规则【免费下载链接】axumHTTP routing and request-handling library for Rust that focuses on ergonomics and modularity项目地址: https://gitcode.com/GitHub_Trending/ax/axumRouter::route是 axum 中把一条路径与一个MethodRouter通常是处理器包装而成的方法路由绑定起来的核心方法它以/分隔的路径段为匹配单元支持静态段、捕获段{key}与通配符段{*key}并在编译期冲突时直接 panic。本文以 route.md 为骨架结合 Router::route 实现、底层 path_router.rs 匹配器与 路由测试 中的真实用例完整讲解路径语法、捕获提取、优先级判定、多方法注册与 panic 边界帮助你写出不冲突、可预测、易维护的路由表。route 方法签名与路径模型在源码中route的文档正是内嵌自本文对应的 route.md#[doc include_str!(../docs/routing/route.md)] #[track_caller] pub fn route(self, path: str, method_router: MethodRouterS) - Self { tap_inner!(self, mut this { panic_on_err!(this.path_router.route(path, method_router)); }) }两个关键点path是由/分隔的路径段组成的字符串每一段要么是静态段要么是捕获段要么是通配符段method_router是负责处理匹配请求的MethodRouter通常由get、post、delete等函数把 handler 包装而成。handler 的具体写法参见 handler 模块文档。底层真正执行注册逻辑的是PathRouter::route见 path_router.rs。值得注意的是如果同一路径上已经注册过MethodRouter再次对同一路径调用route并不会报错而是把新的方法路由合并进已有的路由这正是“逐条添加多方法”能工作的原因下文详解。静态路径精确匹配静态路径是最直观的形式只有请求路径与注册路径逐段完全一致时才会命中对应的服务//foo/users/123例如 hello_world 测试 中注册了/与/users两条静态路由GET /、POST /、POST /users分别命中对应处理器而未注册的路径返回 404。捕获段{key}匹配单个路径段路径中可以出现类似/{key}的段它匹配任意单个段并把该段捕获到key名下/{key}/users/{id}/users/{id}/tweets/avatars/{id}.jpg/avatars/{id}.png捕获段有两条重要规则捕获值不能为空//这种非法路径除外。例如/a/不会匹配/a/{capture}/.png不会匹配/{image}.png。这一点被 suffix_match 测试 直接验证/new-不会命中/new-{id}而/new-1命中。每个段只能有一个捕获但可以带静态前缀和静态后缀。如/avatars/{id}.jpg就是“捕获 后缀”/old-{id}是“前缀 捕获”。捕获值的提取Path 提取器捕获到的值用Path提取器 取出它基于 serde 反序列化自动完成百分号解码解码结果必须是合法 UTF-8否则返回400 Bad Request。官方文档还强调了几个实用结论一个 handler最多只能有一个Path参数但一个Path可以同时提取多个捕获Path((user_id, team_id)): Path(Uuid, Uuid)段标签与结构体字段名按名称匹配#[derive(Deserialize)] struct Params { user_id, team_id }元组则按位置匹配捕获也可以反序列化为HashMap或Vec(String, String)以拿到全部参数用OptionPathT可以让同一个 handler 兼容“有参”和“无参”两条路由。不支持的段匹配无法定义“只匹配数字”或“正则表达式”的段如/users/{id:\d}这类写法是不存在的。类型过滤必须在 handler 内部自行完成例如把Pathu64反序列化失败当作 400 拒绝。若需要拿到“匹配到的路由模板”而非实际请求路径可以使用MatchedPath提取器。前缀/后缀捕获的混合限制带前缀的捕获、带后缀的捕获、或“单捕获同时带前后缀”可以各自存在但不能互相混搭可以混用静态路由和裸捕获。合法的路由集合示例/logo.png、/author.jpg、/{id}.png、/{id}.jpg、/{other_file}—— 但不能加/old-{id}.png或/post-{id}/logo.png、/avatar-{id}.jpg、/{other_file}—— 但不能加/{id}.jpg、/avatar-{id}.png。为什么会有这种限制因为匹配器要保证优先级可判定多个候选路由都能命中同一请求时静态段优先其次是比较静态前缀/后缀长度更长的捕获。若前缀捕获与后缀捕获并存将无法给出确定性的优先顺序因此直接禁止。源码侧由matchit路由树在插入时检测冲突见 path_router.rs 的set_node插入失败会带着Invalid route ... Insertion failed due to conflict...的信息抛 panic。冲突测试可以印证这一规则见 routing/tests/mod.rs{wild}-bar与foo-{wild}冲突foo-{wild}与foo-{wild}-bar冲突{wild}-bar与foo-{wild}-bar冲突。段级优先级的实际验证文档给出了两个段级优先级的例子测试 prefix_suffix_nested_match 完整覆盖请求/ac/a→ 命中/{a}/a第一段的{a}与静态a相比静态段优先……此处实际按“左起第一个出现差异的段”判定请求/abc/a→ 命中/a{c}c/a前缀更长的捕获优先于裸捕获{b}请求/abc/b→ 命中/a{d}c/{*anything}。如果路径因通配符而整体匹配即使其他路由在更右侧的段上“匹配得更好”左起第一个出现差异的段上匹配更优的路由胜出。例如注册/foobar/{*wildcard}与/foo{wildcard}/baz时请求/foobar/baz会命中第一条因为第一个差异段上/foobar的静态前缀更长且整条路径完全匹配。通配符段/{*key}匹配剩余所有段路径可以以/{*key}结尾它匹配其后的所有段并把整段剩余路径捕获到key名下/{*key}/assets/{*path}/{id}/{repo}/{*tree}需要注意/{*key}不匹配“空段”因此/{*key}不匹配/但匹配/a、/a/等/x/{*key}不匹配/x或/x/但匹配/x/a、/x/a/等。这个边界由测试 wildcard_doesnt_match_just_trailing_slash 验证GET /x与GET /x/都返回 404GET /x/foo/bar返回 200 且捕获值为foo/bar。通配符同样通过Path提取use axum::{ Router, routing::get, extract::Path, }; let app: Router Router::new().route(/{*key}, get(handler)); async fn handler(Path(path): PathString) - String { path }注意捕获值不含前导/对路由/foo/{*rest}、请求/foo/bar/bazrest的值是bar/baz。这解释了 wildcard_sees_whole_url 测试中 handler 用Uri提取到的是完整的/api/foo/barUri是原始请求路径而Path是去掉了前缀的捕获值。通配符与 fallback 的交互通配符路由与fallback在底层共享特殊的私有通配符路径/{*__private__axum_fallback}见 mod.rs因此注册顺序会影响行为先fallback(...)再注册/{*wild}会 panic见 colliding_fallback_with_wildcard先注册/{*wild}再设置 fallback 则合法/命中 fallback/x命中通配符路由见 colliding_wildcard_with_fallback。为同一路径接受多个 HTTP 方法两种等价写法一次性添加全部方法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));第二种写法之所以可行正是因为 PathRouter::route 检测到该路径已存在MethodRouter时会调用merge_for_path见 method_routing.rs把新旧方法路由合并而不是报错。源码注释也明确写着“if were adding a newMethodRouterto a route that already has one just merge them”这使.route(/, get(_)).route(/, post(_))得以成立。方法路由的底层是MethodFilter位集GET/POST/PUT/DELETE/HEAD/OPTIONS/PATCH/TRACE/CONNECT/QUERY等见 method_filter.rs也可以直接用on(MethodFilter, handler)精确绑定如on(MethodFilter::GET.or(MethodFilter::POST), root)测试 multiple_methods_for_one_handler。未注册的方法会返回405 Method Not Allowed并带上ALLOW头见 wrong_method_handler 测试。综合示例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): Pathu64) {} async fn do_users_action(Path((version, id)): Path(String, u64)) {} async fn serve_asset(Path(path): PathString) {}Panics何时会在注册阶段崩溃route在构建路由表时而非请求到达时就会 panic#[track_caller]保证 panic 信息指向出错的那一行代码路径与已有路由重叠如两次注册/重叠检测发生在matchit路由树插入阶段panic 信息形如Invalid route /{wild}-bar: Insertion failed due to conflict with previously registered route: /foo-{wild}见 set_node 与冲突测试静态路由与动态路由不算重叠/foo与/{key}可以共存且/foo优先——这是静态与动态路径测试验证过的行为GET /bar命中动态路由GET /foo命中静态路由路径为空或不以/开头会 panic如错误信息为Paths must start with a/. Use / for root routes见 empty_route 测试或Cargo.lock。路径校验逻辑见 validate_path嵌套场景使用Router::nest嵌套路由时内部路径同样是相对段也必须以/开头写/Cargo.lock而非Cargo.lock。此外axum 0.8 默认启用了 v0.7 兼容性检查路径段不能以:或*开头validate_v07_paths见 path_router.rs若确实需要字面匹配这类段可调用Router::without_v07_checks显式关闭检查例如注册/:colon风格的路由。总结静态段、捕获段{key}、通配符段{*key}构成 axum 路径语法的全部要素其中通配符只能出现在路径末尾捕获值通过Path提取器按 serde 规则反序列化支持多参数、元组、结构体与集合类型优先级规则为“静态段 静态前缀/后缀更长的捕获 其他”前缀/后缀捕获混搭会被编译期拒绝同路径多方法既可用get(...).post(...)链式注册也可多次调用route自动合并路径重叠、空路径、非/开头、v0.7 非法段都会在构建路由时 panic善用这些约束可以把错误挡在编译启动阶段。更多相关内容可继续阅读 nest.md、merge.md、fallback.md 与 with_state.md并结合 routing 测试目录 中的用例动手验证。【免费下载链接】axumHTTP routing and request-handling library for Rust that focuses on ergonomics and modularity项目地址: https://gitcode.com/GitHub_Trending/ax/axum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表