Rust Miko 框架系列(四):深入路由系统

Miko 框架系列(四):深入路由系统

注意:此文章主要为了给支持联网搜索的AI提供RAG,此项目还在开发阶段,不建议用于生产。

路由是任何 Web 框架的交通枢纽,它负责将传入的请求引导至正确的处理逻辑。Miko 提供了一套既灵活又直观的路由系统,支持宏定义、模块化、嵌套和中间件等多种高级功能。

1. 定义路由

Miko 主要推荐使用属性宏来定义路由,因为这极大地提升了代码的可读性和开发效率。

使用路由宏

这是最常用、最便捷的方式。

rust 复制代码
use miko::*;
use miko::macros::*;

// 定义一个 GET 路由
#[get("/")]
async fn index() -> &'static str { "Home" }

// 定义一个 POST 路由
#[post("/users")]
async fn create_user() -> StatusCode { StatusCode::CREATED }

// `#[route]` 宏支持指定多种方法
#[route("/data", method = "get, post")]
async fn data_handler() -> &'static str { "Data" }

#[miko]
async fn main() {
    // 当使用 `#[miko]` 宏时,所有路由都会被自动发现和注册
}

Miko 为所有标准的 HTTP 方法都提供了便捷的宏:#[get], #[post], #[put], #[patch], #[delete], #[head], #[options]

手动注册

如果你不希望使用自动注册,或者需要更动态的路由构建方式,也可以手动创建 Router 并注册路由。

rust 复制代码
let router = Router::new()
    .get("/", index)
    .post("/users", create_user);

// `get`, `post` 等方法是 `route(Method::GET, ...)` 的语法糖
let router = router.route(Method::PATCH, "/users/{id}", update_user);

2. 路径参数

从 URL 中捕获动态段落是路由系统的基本功能。

rust 复制代码
use miko::extractor::Path;

// 使用 Path<T> 提取器
#[get("/users/{id}")]
async fn get_user_by_id(Path(id): Path<u32>) -> String {
    format!("Fetching user with ID: {}", id)
}

// 使用 #[path] 宏,代码更简洁
#[get("/users/{id}/posts/{post_id}")]
async fn get_user_post(#[path] id: u32, #[path] post_id: String) -> String {
    format!("Fetching post {} for user {}", post_id, id)
}
  • 顺序很重要 :路径参数是按顺序提取的,而不是按名称。{id}{post_id} 只是占位符,其值会按顺序赋给处理器中的 #[path]Path<T> 参数。
  • 类型安全 :Miko 会尝试将路径段转换为你指定的类型(任何实现了 FromStr 的类型)。如果转换失败(例如,请求 /users/abc 而期望的是 u32),框架会自动返回 400 Bad Request 错误。

3. 模块化与路由组织

当应用规模增长时,将所有路由放在一个文件中会变得难以维护。Miko 提供了强大的模块化能力来组织路由。

使用 #[prefix]

#[prefix] 宏可以为整个 mod 内的所有路由添加一个统一的路径前缀。这是实现 API 版本控制或按功能划分区域的绝佳方式。

rust 复制代码
#[prefix("/api")]
mod api {
    use super::*;

    #[get("/status")] // 完整路径: /api/status
    async fn status() -> &'static str { "OK" }

    #[prefix("/v1")] // 支持嵌套
    mod v1 {
        use super::*;
        #[get("/users")] // 完整路径: /api/v1/users
        async fn list_users() -> &'static str { "List of V1 users" }
    }
}

#[miko]
async fn main() {
    // 所有带 `#[prefix]` 的模块路由都会被正确组合和注册
}

使用 Router::nestRouter::merge

如果你采用手动注册路由的方式,可以使用 nestmerge 来组合不同的路由模块。

  • nest: 为一个子路由器的所有路径添加前缀。
  • merge: 将一个路由器的所有路由合并到当前路由器中。
rust 复制代码
// a_routes.rs
pub fn router() -> Router {
    Router::new().get("/a", handler_a)
}

// b_routes.rs
pub fn router() -> Router {
    Router::new().get("/b", handler_b)
}

// main.rs
let a_router = a_routes::router();
let b_router = b_routes::router();

let router = Router::new()
    .nest("/prefix", a_router) // 产生 /prefix/a
    .merge(b_router);          // 产生 /b

4. 路由与中间件

Miko 与 Tower 中间件生态无缝集成。你可以将中间件(Layer)应用到不同层级的路由上。

全局中间件

直接在主路由器上应用 layer,它将作用于所有请求。

rust 复制代码
use tower_http::trace::TraceLayer;

let router = Router::new()
    .get("/", index)
    .layer(TraceLayer::new_for_http()); // 应用于所有路由

路由组中间件

为一个特定的路由集合应用中间件。

rust 复制代码
let admin_routes = Router::new()
    .get("/dashboard", admin_dashboard)
    .post("/settings", update_settings)
    .layer(require_admin_auth_layer()); // 只对 admin_routes 生效

let router = Router::new()
    .get("/", index)
    .nest("/admin", admin_routes);

单个路由或模块中间件 (#[layer])

使用 #[layer] 宏,可以将中间件直接附加到单个处理器或整个模块上。

rust 复制代码
use tower_http::timeout::TimeoutLayer;
use std::time::Duration;

// 应用于单个路由
#[get("/slow_operation")]
#[layer(TimeoutLayer::new(Duration::from_secs(10)))]
async fn slow_operation() { /* ... */ }

// 应用于整个模块
#[prefix("/api")]
#[layer(TimeoutLayer::new(Duration::from_secs(5)))]
mod api {
    #[get("/data")] // 这个路由会自动拥有 5 秒超时
    async fn get_data() { /* ... */ }
}

应用顺序 :当存在多个 #[layer] 时,它们的声明顺序是从上到下,但应用顺序是从内到外。即最靠近处理器函数的 #[layer] 最先生效。

5. 路由优先级

Miko 的路由匹配遵循一个简单的规则:静态路径优先于动态路径

rust 复制代码
let router = Router::new()
    .get("/users/me", get_current_user) // 静态路径
    .get("/users/{id}", get_user_by_id); // 动态路径

当一个请求 GET /users/me 到达时,它会优先匹配 /users/me 这条路由,而不是 /users/{id}。这让你可以在通用规则之上定义特殊的静态路由。

总结

Miko 的路由系统通过强大的宏和对 Tower 生态的良好支持,提供了一套兼具易用性和灵活性的解决方案。无论是简单的个人项目还是复杂的大型应用,你都可以通过 #[prefix]#[layer]Router 组合,构建出清晰、可维护的路由结构。


下一篇预告:Miko 框架系列(五):请求提取与数据验证

相关推荐
用户68545375977692 小时前
布隆过滤器删不掉数据?布谷鸟过滤器:让我来!🐦
后端
虎子_layor2 小时前
号段模式(分布式ID)上手指南:从原理到实战
java·后端
烽学长2 小时前
(附源码)基于Spring boot的校园志愿服务管理系统的设计与实现
java·spring boot·后端
shark_chili2 小时前
硬核安利一个监控告警开源项目Nightingale
后端
IT_陈寒2 小时前
WeaveFox 全栈创作体验:从想法到完整应用的零距离
前端·后端·程序员
程序员爱钓鱼2 小时前
Python编程实战 - Python实用工具与库 - 正则表达式匹配(re 模块)
后端·python·面试
程序员爱钓鱼2 小时前
Python编程实战 - Python实用工具与库 - 爬取并存储网页数据
后端·python·面试
Ryan ZX2 小时前
【Go语言基础】序列化和反序列化
开发语言·后端·golang
回家路上绕了弯2 小时前
跨境数据延迟高?5 大技术方向 + 实战案例帮你解决
分布式·后端