在当今的微服务架构和云原生时代,高性能、安全的 API 服务是每个后端开发者的必备技能。Rust 语言以其卓越的性能、内存安全和并发特性,正迅速成为构建关键基础设施的首选语言。本文将带你从零开始,使用 Rust 和 Actix-web 框架构建一个完整的 REST API 服务,涵盖从项目初始化到生产部署的全过程。
为什么选择 Rust 和 Actix-web?
Rust 的优势
- 零成本抽象:高级特性不带来运行时开销
- 内存安全:编译时保证内存安全,无数据竞争
- 卓越性能:与 C/C++ 相当,远超其他高级语言
- 强大的类型系统:减少运行时错误
- 优秀的并发支持:无畏并发(Fearless Concurrency)
Actix-web 的特点
- 高性能:基于 Actor 模型,支持异步/等待
- 类型安全:充分利用 Rust 的类型系统
- 丰富的生态:中间件、路由、WebSocket 等一应俱全
- 生产就绪:被多家知名公司用于生产环境
项目实战:构建用户管理系统 API
1. 环境准备与项目初始化
首先确保安装了 Rust 工具链:
# 安装 Rust(如果尚未安装)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 创建新项目
cargo new user-management-api
cd user-management-api
# 添加依赖
cargo add actix-web
cargo add serde --features derive
cargo add serde_json
cargo add chrono --features serde
cargo add uuid --features "serde v4"
cargo add sqlx --features "runtime-tokio-rustls postgres"
cargo add dotenv
cargo add bcrypt
cargo add jsonwebtoken
cargo add validator --features derive
2. 项目结构设计
user-management-api/
├── src/
│ ├── main.rs # 应用入口
│ ├── models/ # 数据模型
│ │ ├── mod.rs
│ │ ├── user.rs
│ │ └── response.rs
│ ├── handlers/ # 请求处理器
│ │ ├── mod.rs
│ │ └── user_handler.rs
│ ├── database/ # 数据库相关
│ │ ├── mod.rs
│ │ └── connection.rs
│ ├── middleware/ # 中间件
│ │ ├── mod.rs
│ │ └── auth.rs
│ ├── utils/ # 工具函数
│ │ ├── mod.rs
│ │ └── validation.rs
│ └── config/ # 配置管理
│ ├── mod.rs
│ └── settings.rs
├── migrations/ # 数据库迁移
│ └── 20240101000000_create_users.sql
├── .env.example # 环境变量示例
├── .env # 环境变量(本地开发)
├── Cargo.toml # 依赖管理
└── Dockerfile # 容器化配置
3. 核心代码实现
3.1 数据模型定义
// src/models/user.rs
use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};
use uuid::Uuid;
use validator::Validate;
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct User {
pub id: Uuid,
#[validate(email)]
pub email: String,
#[validate(length(min = 3, max = 50))]
pub username: String,
#[serde(skip_serializing)]
pub password_hash: String,
pub is_active: bool,
pub is_admin: bool,
#[serde(with = "chrono::serde::ts_seconds")]
pub created_at: DateTime<Utc>,
#[serde(with = "chrono::serde::ts_seconds")]
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Deserialize, Validate)]
pub struct CreateUserRequest {
#[validate(email)]
pub email: String,
#[validate(length(min = 3, max = 50))]
pub username: String,
#[validate(length(min = 8))]
pub password: String,
}
#[derive(Debug, Deserialize, Validate)]
pub struct UpdateUserRequest {
#[validate(email)]
pub email: Option<String>,
#[validate(length(min = 3, max = 50))]
pub username: Option<String>,
#[validate(length(min = 8))]
pub password: Option<String>,
}
#[derive(Debug, Deserialize, Validate)]
pub struct LoginRequest {
#[validate(email)]
pub email: String,
#[validate(length(min = 8))]
pub password: String,
}
3.2 数据库连接与迁移
// src/database/connection.rs
use sqlx::postgres::{PgPool, PgPoolOptions};
use std::time::Duration;
use crate::config::Settings;
pub type DbPool = PgPool;
pub async fn create_pool(settings: &Settings) -> Result<DbPool, sqlx::Error> {
PgPoolOptions::new()
.max_connections(settings.database.max_connections)
.min_connections(settings.database.min_connections)
.max_lifetime(Duration::from_secs(settings.database.max_lifetime))
.connect_timeout(Duration::from_secs(settings.database.connect_timeout))
.connect(&settings.database.url)
.await
}
// migrations/20240101000000_create_users.sql
CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
username VARCHAR(100) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
is_active BOOLEAN DEFAULT true,
is_admin BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_username ON users(username);
3.3 用户处理器实现
// src/handlers/user_handler.rs
use actix_web::{web, HttpResponse, Responder};
use serde_json::json;
use crate::models::{User, CreateUserRequest, UpdateUserRequest};
use crate::database::DbPool;
use crate::utils::validation::validate_request;
use bcrypt::{hash, verify, DEFAULT_COST};
use uuid::Uuid;
pub struct UserHandler;
impl UserHandler {
// 创建用户
pub async fn create(
pool: web::Data<DbPool>,
user_data: web::Json<CreateUserRequest>,
) -> impl Responder {
// 验证请求数据
if let Err(errors) = validate_request(&user_data) {
return HttpResponse::BadRequest().json(json!({
"error": "Validation failed",
"details": errors
}));
}
// 检查邮箱是否已存在
let existing_user = sqlx::query!("SELECT id FROM users WHERE email = $1", user_data.email)
.fetch_optional(pool.get_ref())
.await;
if let Ok(Some(_)) = existing_user {
return HttpResponse::Conflict().json(json!({
"error": "Email already exists"
}));
}
// 哈希密码
let password_hash = match hash(&user_data.password, DEFAULT_COST) {
Ok(hash) => hash,
Err(_) => return HttpResponse::InternalServerError().finish(),
};
// 插入用户
let user_id = Uuid::new_v4();
match sqlx::query!(
r#"
INSERT INTO users (id, email, username, password_hash)
VALUES ($1, $2, $3, $4)
RETURNING id, email, username, is_active, is_admin, created_at, updated_at
"#,
user_id,
user_data.email,
user_data.username,
password_hash
)
.fetch_one(pool.get_ref())
.await
{
Ok(record) => {
let user = User {
id: record.id,
email: record.email,
username: record.username,
password_hash: "".to_string(), // 不返回密码哈希
is_active: record.is_active,
is_admin: record.is_admin,
created_at: record.created_at,
updated_at: record.updated_at,
};
HttpResponse::Created().json(user)
}
Err(e) => {
eprintln!("Database error: {}", e);
HttpResponse::InternalServerError().finish()
}
}
}
// 获取用户列表(