欢迎光临
我们一直在努力

Rocket 0.5 上手到路由、请求校验、响应构建、状态管理与 Fairings 中间件

1. 快速跑起来:Hello Rocket

初始化项目:

cargo new hello-rocket –bin
cd hello-rocket

Cargo.toml 添加依赖:

[dependencies]
rocket = "0.5.1"

main.rs:

#[macro_use] extern crate rocket;

#[get("/")]
fn index() -> &'static str {
"Hello, world!"
}

#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![index])
}

运行:

cargo run

访问 http://127.0.0.1:8000/ 即可看到返回。

你会注意到 Rocket 的“入口”不是写一个 main 然后手工起 server,而是用 #[launch] 生成 main 并启动异步运行时(tokio)。

2. Rocket 的生命周期:从 Request 到 Response

Rocket 把一次请求处理抽象成四步:

  • Routing:路由匹配
  • Validation:各种 Guard 校验(参数、Header、Body、策略等)
  • Processing:调用 handler 执行业务逻辑
  • Response:把 handler 的返回值转换成 HTTP 响应并发回
  • 理解这个顺序很关键:你写的 handler 其实只负责第 3 步;第 1/2/4 步主要由 Rocket 通过宏生成代码来完成。

    3. Routing:声明式路由与 Mount

    最基础的路由:

    #[get("/world")]
    fn world() -> &'static str {
    "hello, world!"
    }

    Mount 到 base path:

    rocket::build().mount("/hello", routes![world]);

    请求 GET /hello/world 才会命中。

    Mount 可以链式调用,同一个 route 也可以挂多个前缀:

    rocket::build()
    .mount("/hello", routes![world])
    .mount("/hi", routes![world]);

    4. Requests:把“校验”写进类型系统

    Rocket 最舒服的地方在于:路由属性(路径/方法/format/data 等)+ 函数签名(参数类型、guard 类型)一起描述“什么请求才算合法”。

    4.1 方法与动态路径

    动态路径参数:

    #[get("/hello/<name>")]
    fn hello(name: &str) -> String {
    format!("Hello, {}!", name)
    }

    多个动态参数,直接用 Rust 类型做校验:

    #[get("/hello/<name>/<age>/<cool>")]
    fn hello(name: &str, age: u8, cool: bool) -> String {
    if cool {
    format!("You're a cool {} year old, {}!", age, name)
    } else {
    format!("{}, we need to talk about your coolness.", name)
    }
    }

    age 不是 u8、cool 不是 bool 时会发生什么?Rocket 会把请求“转发”(forward)给下一个同样能匹配路径的方法更低优先级的路由。

    4.2 Rank:解决路由碰撞与转发链

    同一路径不同参数类型的典型写法:

    #[get("/user/<id>")]
    fn user(id: usize) { /* … */ }

    #[get("/user/<id>", rank = 2)]
    fn user_int(id: isize) { /* … */ }

    #[get("/user/<id>", rank = 3)]
    fn user_str(id: &str) { /* … */ }

    命中顺序:rank 越小越优先(默认 rank 是负数范围,越小越优先)。参数解析失败会 forward 到下一个候选路由,直到成功或最终触发 catcher。

    4.3 Request Guards:把鉴权/策略封装成类型

    Request Guard 的本质:实现 FromRequest 的类型。只要把它放进 handler 参数列表里,Rocket 就会自动执行校验。

    #[get("/admin")]
    fn admin_panel(admin: AdminUser) -> &'static str {
    "admin"
    }

    建议:鉴权这种“不是所有路由都需要”的事情,优先用 Guard,而不是 Fairing(除非你真的需要全站强制鉴权)。

    4.4 Body Data:Json/Form/TempFile/Data

    JSON 入参:开启 rocket 的 json feature,然后用 Json<T>(T 需 Deserialize):

    use rocket::serde::{Deserialize, json::Json};

    #[derive(Deserialize)]
    #[serde(crate = "rocket::serde")]
    struct Task<'r> {
    description: &'r str,
    complete: bool
    }

    #[post("/todo", data = "<task>", format = "json")]
    fn new(task: Json<Task<'_>>) { /* … */ }

    表单:Form<T> + FromForm 派生(支持 multipart / x-www-form-urlencoded):

    use rocket::form::Form;

    #[derive(FromForm)]
    struct Task<'r> {
    complete: bool,
    r#type: &'r str,
    }

    #[post("/todo", data = "<task>")]
    fn new(task: Form<Task<'_>>) { /* … */ }

    上传文件:TempFile 直接落临时文件,想持久化就 persist_to()。

    流式读取 body:用 Data,并且必须显式设置读取上限(防止 DoS)。

    4.5 Query Strings:像表单一样强大

    Query 参数其实就是“URL 上的表单字段”,支持嵌套/集合。基本形态:

    #[get("/?<name>&<color>&<other>")]
    fn hello(name: &str, color: Vec<Color>, other: Option<usize>) { /* … */ }

    4.6 Error Catchers:统一错误出口

    use rocket::Request;

    #[catch(404)]
    fn not_found(req: &Request) -> String {
    format!("'{}' not found", req.uri())
    }

    #[launch]
    fn rocket() -> _ {
    rocket::build().register("/", catchers![not_found])
    }

    catcher 有 scope(register 的 base path),base 越长越优先。

    5. Responses:返回值“看起来随便”,其实很讲究

    Rocket 允许 handler 返回任何实现了 Responder 的类型:&str、String、Json<T>、NamedFile、Redirect、Status、Result/Option 组合等。

    5.1 包装 Responder:status/content 的组合

    比如设置状态码 + Content-Type:

    use rocket::http::{Status, ContentType};

    #[get("/")]
    fn json() -> (Status, (ContentType, &'static str)) {
    (Status::ImATeapot, (ContentType::JSON, r#"{ "hi": "world" }"#))
    }

    也可以 derive 一个自定义 responder(更可复用)。

    5.2 Option / Result:把“找不到/失败”变成语义

    Option<T>:None 自动变 404
    Result<T, E>:Ok/Err 各自响应(E 也得是 Responder)

    这让你写“文件服务器”这类逻辑非常简洁。

    5.3 Async Streams / WebSockets / Templates / uri!

    Rocket 0.5 在流式响应(SSE/ReaderStream/TextStream)和 WebSocket(rocket_ws)上都挺顺手。模板用 rocket_dyn_templates::Template,URI 生成用 uri!,能在编译期校验参数/类型,避免手拼字符串出 bug。

    6. State:全局状态与请求级状态

    Rocket 把 state 分两类:Managed State(全局)与 Request-Local State(请求内缓存)。

    6.1 Managed State:全局共享、按类型唯一

    注册:

    rocket::build().manage(MyState { /* … */ })

    使用:在 handler 里加 &State<T>:

    use rocket::State;

    #[get("/count")]
    fn count(st: &State<HitCount>) -> String { /* … */ }

    注意:必须 Send + Sync,因为 Rocket 多线程并发访问。

    6.2 Request-Local State:一次请求内生成一次、复用多次

    request.local_cache(|| …):同类型在一个请求里只会初始化一次,后续复用,非常适合“请求级 ID”“鉴权结果缓存”等。

    7. Fairings:Rocket 的结构化中间件

    Fairings 是 Rocket 的 middleware 体系,但它有边界:

  • 不能直接终止请求并返回响应
  • 不能给单个请求注入“任意非请求数据”(这更像 Guard 的活)
  • 可以阻止应用启动(ignite 阶段做校验)
  • 可以检查/修改配置(ignite 阶段很常用)
  • 经验法则:Fairing 做“全局性事情”,例如统一安全头、统一日志、统计、压缩、CORS、请求耗时、全站 trace id、启动时配置校验。鉴权优先用 Guard,除非你就是要全站强制鉴权。

    7.1 五类回调(按生命周期)

    • on_ignite:点火阶段,能改 Rocket 实例,常用来解析/校验配置、塞进 Managed State
    • on_liftoff:启动后立即触发,适合启动伴生服务、打日志
    • on_request:请求刚到,能改 request、看部分 data,但不能直接响应
    • on_response:响应即将发出,可重写响应、加 header、把 404 改成你想要的样子
    • on_shutdown:触发优雅停机时调用,常用清理资源/通知外部系统

    Fairing 的执行顺序:按 attach 顺序,越先 attach 越先执行。

    7.2 一个实用的 Fairing:全站 RequestId + 响应头注入

    这就是“Fairing + Request-Local State”最常见的组合:每个请求生成一次 request id,并在 response 里注入 X-Request-Id。

    核心思路:

    • 在 on_request 里触发 local_cache 创建 ID
    • 在 on_response 里读出同一个 ID 写到 header

    (你之前我给的 demo 骨架里已经包含了这段实现。)

    7.3 统计计数器:用 Fairing 避免污染 handler 签名

    像 GET/POST 次数统计这种“全局行为”,Fairing 比 Guard 更合适,因为你不想每个路由都加参数。

    请求阶段统计,响应阶段把某个 404 路径改写成统计结果,是一个很典型的“response fairing 重写 404”用法。

    7.4 AdHoc Fairings:轻量版本

    当你只是想挂一个小闭包做点事,AdHoc 会比手写 Fairing trait 省事很多:

    • AdHoc::on_ignite(…)
    • AdHoc::on_liftoff(…)
    • AdHoc::on_request(…)
    • AdHoc::on_response(…)
    • AdHoc::on_shutdown(…)

    非常适合:启动打印、简单 header 注入、临时调试、配置检查等。

    8. 一个落地建议:Rocket 的“正确分层姿势”

    你写业务时可以按这个优先级选工具:

  • 路由匹配与参数类型校验:交给 route attribute + 参数类型
  • 认证/授权/策略:优先 Request Guard(可组合、可测试、可局部使用)
  • 入参解析:优先 Data Guard(Json/Form/TempFile/Data)
  • 出参构建:Responder 组合(Option/Result/status/content/Json/Template/Stream)
  • 全局通用逻辑:Fairing(统一头、trace、metrics、CORS、压缩、启动校验)
  • 全局共享资源:Managed State(配置、HTTP client、队列、缓存、服务对象)
  • 单请求缓存:Request-Local State(request id、鉴权结果、耗时统计上下文)
  • 赞(0)
    未经允许不得转载:171主机测评 » Rocket 0.5 上手到路由、请求校验、响应构建、状态管理与 Fairings 中间件
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址