Rust Rocket Web 框架
Rocket 是 Rust 生态非常流行的Web服务框架,主打开发体验好、类型安全、编译期检查,面向 REST API、Web应用。
注意:Rocket 分两个大版本:
- Rocket 0.4:基于老版本 Rust,使用 nightly Rust,已经停止维护
- Rocket 0.5‑rc(现在主流):稳定版,支持稳定 Rust,是目前项目使用版本
核心特点
- 编译期安全:路由、参数、请求处理全部在编译时校验,很多错误运行前就暴露。
- 宏驱动,代码简洁:
#[get]、#[post]宏定义路由,写法非常直观。 - 内置全套能力:JSON序列化/反序列化、表单、Cookie、Session、静态文件、数据库集成、TLS、中间件、状态管理。
- 类型提取器(Guard):
FromRequest机制,自动从请求提取参数、身份校验,不用手动解析request。 - 异步支持:0.5 基于 tokio 异步运行时,高性能。
- 内置JSON:依赖 serde,直接返回结构体自动序列化为json。
简单Hello World示例(0.5)
Cargo.toml
toml
[package]
name = "rocket-demo"
version = "0.1.0"
edition = "2021"
[dependencies]
rocket = "0.5.0-rc.3"src/main.rs
rust
#[macro_use]
extern crate rocket;
#[get("/")]
fn index() -> &'static str {
"Hello Rocket!"
}
#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![index])
}运行后访问 http://127.0.0.1:8000。
常用功能演示
1. URL路径参数
rust
#[get("/hello/<name>")]
fn hello(name: &str) -> String {
format!("Hello, {}!", name)
}2. 返回JSON(需要serde)
toml
rocket = { version = "0.5.0-rc.3", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }rust
use rocket::serde::json::Json;
use serde::Serialize;
#[derive(Serialize)]
struct User {
id: u64,
name: String,
}
#[get("/user")]
fn get_user() -> Json<User> {
Json(User {
id: 1,
name: "Alice".into(),
})
}3. POST接收JSON
rust
#[post("/user", data = "<user>")]
fn create_user(user: Json<User>) -> Json<User> {
user
}4. 状态共享(全局状态)
rust
#[launch]
fn rocket() -> _ {
rocket::build()
.manage(String::from("全局配置"))
.mount("/", routes![show_state])
}
#[get("/state")]
fn show_state(state: &State<String>) -> String {
state.to_string()
}5. 请求Guard(权限校验)
实现FromRequest,可以做登录鉴权,自动拦截非法请求,不需要每个接口写if判断。
重要概念
- Routes(路由):
#[get]#[post]#[put]#[delete] - Mount:挂载路由,设置路由前缀,例如
.mount("/api", routes![xxx]) - State:全局应用状态,数据库连接池、配置等。
- Guard(提取器):
FromRequest,从Request里提取数据,鉴权、解析token。 - Fairing:火箭的中间件,全局钩子,请求前后处理,日志、CORS、初始化数据库。
- Responder:响应实现,自定义返回类型。
生态与数据库
Rocket 官方配套 rocket_sync_db_pools 数据库连接池,支持 PostgreSQL、MySQL、SQLite。
toml
rocket_sync_db_pools = { version = "0.1.0-rc.3", features = ["postgres"] }配置在 Rocket.toml 文件中写数据库连接。
Rocket 优缺点
✅ 优点
- Rust Web框架里开发体验最好,语法简洁,上手快
- 编译期校验,少运行时bug
- 内置丰富功能,不用大量找第三方库
- 异步tokio,性能优秀
- 文档非常完善
❌ 缺点
- 0.5 版本长期rc,正式版迟迟没出(但是rc版本生产可用)
- 相比 axum,抽象层更高,性能略低一点;axum更偏底层,Rocket更偏应用层
- 部分高级自定义需要理解Rocket内部抽象
和其他Rust Web框架对比
| 框架 | 特点 |
|---|---|
| Rocket | 高层封装,开发友好,内置功能多,适合快速写API、业务服务 |
| axum | tokio生态,轻量底层,性能极高,生态灵活,适合高性能服务 |
| warp | 基于hyper,函数式风格,组合式路由 |
选型建议:
- 快速开发业务API、后台服务,想要少写样板代码 → Rocket
- 追求极致性能、高度自定义、微服务 → axum
部署
Rocket支持:
- 直接编译二进制,无依赖,部署简单
- 支持TLS,可搭配nginx反向代理
- 环境变量配置,
Rocket.toml区分开发/生产环境。
REST API 完整示例
版本:
0.5.0‑rc.3,使用稳定 Rust,包含:CORS、JWT登录鉴权、PostgreSQL数据库、用户CRUD、请求Guard、配置文件。
1. Cargo.toml
toml
[package]
name = "rocket-rest-demo"
version = "0.1.0"
edition = "2021"
[dependencies]
rocket = { version = "0.5.0-rc.3", features = ["json"] }
rocket_sync_db_pools = { version = "0.1.0-rc.3", features = ["postgres"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
jsonwebtoken = "9.2"
chrono = { version = "0.4", features = ["serde"] }
dotenv = "0.15"
rocket_cors = "0.5.0-rc.3"2. Rocket.toml(配置文件,项目根目录)
toml
[default]
address = "127.0.0.1"
port = 8000
log_level = "debug"
[default.databases]
db = { url = "postgres://postgres:123456@localhost:5432/rocket_demo" }
[production]
log_level = "info"
[development]
log_level = "debug"3. 数据库迁移 SQL
创建数据库 rocket_demo,执行:
sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password_hash VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE
);4. src/main.rs 完整代码
rust
#[macro_use]
extern crate rocket;
use rocket::{
http::Status,
serde::json::Json,
State,
FromRequest,
Request,
Outcome,
};
use rocket_sync_db_pools::database;
use rocket_cors::{AllowedOrigins, CorsOptions};
use serde::{Deserialize, Serialize};
use jsonwebtoken::{encode, EncodingKey, Header, Validation, decode, DecodingKey};
use chrono::{Utc, Duration};
// ===================== 数据库连接 =====================
#[database("db")]
pub struct DbConn(rocket_sync_db_pools::diesel::PgConnection);
// ===================== 模型 =====================
#[derive(Debug, Serialize, Deserialize)]
pub struct User {
pub id: i32,
pub username: String,
pub email: String,
}
#[derive(Debug, Deserialize)]
pub struct RegisterReq {
pub username: String,
pub password: String,
pub email: String,
}
#[derive(Debug, Deserialize)]
pub struct LoginReq {
pub username: String,
pub password: String,
}
#[derive(Debug, Serialize)]
pub struct TokenResp {
pub token: String,
}
// ===================== JWT 配置 全局状态 =====================
#[derive(Clone)]
pub struct JwtConfig {
pub secret: String,
}
// ===================== Guard:鉴权提取器,需要登录的接口自动校验token =====================
#[derive(Debug)]
pub struct AuthUser {
pub user_id: i32,
}
#[rocket::async_trait]
impl<'r> FromRequest<'r> for AuthUser {
type Error = ();
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
let auth_header = match req.headers().get_one("Authorization") {
Some(h) => h,
None => return Outcome::Error((Status::Unauthorized, ())),
};
let token = match auth_header.strip_prefix("Bearer ") {
Some(t) => t,
None => return Outcome::Error((Status::Unauthorized, ())),
};
let jwt_config = match req.rocket().state::<JwtConfig>() {
Some(c) => c,
None => return Outcome::Error((Status::InternalServerError, ())),
};
let decoding_key = DecodingKey::from_secret(jwt_config.secret.as_bytes());
let token_data = match decode::<serde_json::Value>(token, &decoding_key, &Validation::default()) {
Ok(d) => d,
Err(_) => return Outcome::Error((Status::Unauthorized, ())),
};
let user_id = match token_data.claims["user_id"].as_i64() {
Some(id) => id as i32,
None => return Outcome::Error((Status::Unauthorized, ())),
};
Outcome::Success(AuthUser { user_id })
}
}
// ===================== 接口路由 =====================
/// 注册用户
#[post("/register", data = "<req>")]
async fn register(conn: DbConn, req: Json<RegisterReq>) -> Result<Json<User>, Status> {
// 这里简单演示,生产环境务必使用bcrypt做密码哈希,不要明文存储
let user: User = conn.run(move |c| {
diesel::insert_into(users::table)
.values((
users::username.eq(&req.username),
users::password_hash.eq(&req.password),
users::email.eq(&req.email),
))
.returning((users::id, users::username, users::email))
.get_result(c)
.map(|(id, username, email)| User { id, username, email })
}).await.map_err(|_| Status::InternalServerError)?;
Ok(Json(user))
}
/// 登录获取JWT Token
#[post("/login", data = "<req>")]
async fn login(conn: DbConn, jwt_cfg: &State<JwtConfig>, req: Json<LoginReq>) -> Result<Json<TokenResp>, Status> {
let user: Option<User> = conn.run(move |c| {
users::table
.filter(users::username.eq(&req.username))
.filter(users::password_hash.eq(&req.password))
.select((users::id, users::username, users::email))
.first(c)
.optional()
}).await.map_err(|_| Status::InternalServerError)?;
let user = user.ok_or(Status::Unauthorized)?;
let exp = Utc::now() + Duration::hours(24);
let claims = serde_json::json!({
"user_id": user.id,
"exp": exp.timestamp()
});
let token = encode(
&Header::default(),
&claims,
&EncodingKey::from_secret(jwt_cfg.secret.as_bytes()),
).map_err(|_| Status::InternalServerError)?;
Ok(Json(TokenResp { token }))
}
/// 需要登录才能访问:获取当前用户信息
#[get("/me")]
async fn get_me(conn: DbConn, auth: AuthUser) -> Result<Json<User>, Status> {
let user = conn.run(move |c| {
users::table
.filter(users::id.eq(auth.user_id))
.select((users::id, users::username, users::email))
.first(c)
}).await.map_err(|_| Status::InternalServerError)?;
Ok(Json(user))
}
/// 公开接口,无需登录
#[get("/health")]
fn health() -> &'static str {
"ok"
}
// ===================== 启动服务:CORS、全局状态、数据库、挂载路由 =====================
#[launch]
fn rocket() -> _ {
// CORS配置
let cors = CorsOptions::default()
.allowed_origins(AllowedOrigins::all())
.allow_credentials(true);
rocket::build()
.attach(DbConn::fairing())
.attach(cors.to_cors().unwrap())
.manage(JwtConfig {
secret: "my_super_secret_key_123456".to_string(),
})
.mount("/api", routes![register, login, get_me, health])
}
// diesel 表定义,放在文件末尾
mod users {
use diesel::table;
table! {
users (id) {
id -> Int4,
username -> Varchar,
password_hash -> Varchar,
email -> Varchar,
}
}
}5. 运行与测试
- 启动PostgreSQL,建好数据库
rocket_demo,执行上面建表SQL - 修改
Rocket.toml里数据库账号密码 cargo run,服务启动http://127.0.0.1:8000/api
接口测试示例
- 注册
POST /api/register
{
"username":"test",
"password":"123456",
"email":"test@example.com"
}- 登录拿token
POST /api/login
{
"username":"test",
"password":"123456"
}- 访问需要鉴权接口,请求头带上:
Authorization: Bearer 你的token
GET /api/me⚠️生产环境重要提醒
- 密码不要明文存储,示例只是演示,实际使用
bcrypt做哈希 - JWT密钥不要硬编码,使用环境变量传入
- 调整CORS:不要使用
AllowedOrigins::all(),限定允许的前端域名 - 数据库错误处理完善,增加参数校验
- Rocket 0.5‑rc 虽然可以上生产,但留意官方更新
关键知识点回顾
DbConn:rocket_sync_db_pools 数据库连接池,run()执行数据库操作FromRequestGuard:鉴权提取器,函数参数写AuthUser就自动做token校验,不用每个接口写重复鉴权代码- Fairing:中间件,这里挂载CORS、数据库初始化
State<T>:全局单例状态,存放JWT密钥、配置等全局对象
如果你需要,我可以给你:
- 改造为axum版本对比
- 增加分页、错误统一返回、日志、完整的crud
- 或者docker部署配置