基于 Rust 的Actix Web 框架的应用与优化实例
Actix Web 框架概述
Actix Web 是一个基于 Rust 的高性能、轻量级 Web 框架,构建于 Actix 异步运行时之上。它支持异步编程模型,适合构建高并发、低延迟的 Web 服务和 API。
核心特性
- 异步支持:基于
async/await
语法,充分利用 Rust 的异步生态。 - 高性能:底层使用 actor 模型和零成本抽象,性能接近原生代码。
- 类型安全:通过 Rust 的类型系统确保路由、请求和响应的安全性。
- 灵活的路由:支持 RESTful 路由、动态路径参数和中间件。
- WebSocket 支持:内置 WebSocket 协议支持。
基本项目结构
典型的 Actix Web 项目结构如下:
src/
├── main.rs # 应用入口和路由配置
├── handlers.rs # 请求处理逻辑
├── models.rs # 数据模型
└── lib.rs # 模块定义(可选)
快速入门示例
以下是一个最小化的 Actix Web 应用代码:
use actix_web::{get, App, HttpResponse, HttpServer, Responder};
#[get("/")]
async fn hello() -> impl Responder {
HttpResponse::Ok().body("Hello, Actix Web!")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().service(hello))
.bind("127.0.0.1:8080")?
.run()
.await
}
关键组件
路由与处理函数
- 使用
#[get]
、#[post]
等宏定义路由。 - 处理函数返回
impl Responder
,支持多种响应类型(如HttpResponse
、String
)。
- 使用
状态共享
通过Data<T>
类型共享全局状态(如数据库连接池):App::new() .app_data(Data::new(AppState { db: pool }))
中间件
使用wrap
添加中间件(如日志、认证):App::new() .wrap(Logger::default())
错误处理
自定义错误类型并实现ResponseError
trait:impl ResponseError for MyError { fn error_response(&self) -> HttpResponse { HttpResponse::InternalServerError().finish() } }
安装 Actix Web 依赖 在 Cargo.toml
中添加以下依赖:
[dependencies]
actix-web = "4"
创建基础 HTTP 服务器
use actix_web::{get, App, HttpResponse, HttpServer, Responder};
#[get("/")]
async fn hello() -> impl Responder {
HttpResponse::Ok().body("Hello world!")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().service(hello))
.bind(("127.0.0.1", 8080))?
.run()
.await
}
路由处理示例
多路由配置
use actix_web::{web, App, HttpResponse, HttpServer};
async fn index() -> HttpResponse {
HttpResponse::Ok().body("Index page")
}
async fn about() -> HttpResponse {
HttpResponse::Ok().body("About page")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/", web::get().to(index))
.route("/about", web::get().to(about))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
路径参数提取
use actix_web::{get, web, App, HttpServer};
#[get("/users/{user_id}/{friend}")]
async fn user_info(path: web::Path<(u32, String)>) -> String {
let (user_id, friend) = path.into_inner();
format!("User {}'s friend: {}", user_id, friend)
}
以下是基于Rust的路由处理示例,涵盖不同框架和场景的实用案例。示例分为基础路由、动态参数、中间件、错误处理等类别,代码均以实际可运行为目标。
基础路由(axum框架)
use axum::{Router, routing::get, Json};
use serde_json::json;
async fn hello_world() -> Json<serde_json::Value> {
Json(json!({ "message": "Hello, world!" }))
}
#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(hello_world));
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
动态路径参数
use axum::{Router, routing::get, extract::Path};
async fn user_info(Path(user_id): Path<u32>) -> String {
format!("User ID: {}", user_id)
}
let app = Router::new().route("/users/:user_id", get(user_info));
查询参数处理
use axum::{Router, routing::get, extract::Query};
use serde::Deserialize;
#[derive(Deserialize)]
struct Pagination {
page: usize,
per_page: usize,
}
async fn list_items(Query(pagination): Query<Pagination>) -> String {
format!("Page: {}, Per Page: {}", pagination.page, pagination.per_page)
}
let app = Router::new().route("/items", get(list_items));
JSON请求体处理
use axum::{Router, routing::post, Json, extract::Extension};
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
struct CreateUser {
name: String,
}
#[derive(Serialize)]
struct User {
id: u64,
name: String,
}
async fn create_user(Json(input): Json<CreateUser>) -> Json<User> {
Json(User { id: 1, name: input.name })
}
let app = Router::new().route("/users", post(create_user));
中间件示例(日志记录)
use axum::{Router, routing::get, middleware};
use tower_http::trace::TraceLayer;
async fn handler() -> &'static str { "OK" }
let app = Router::new()
.route("/", get(handler))
.layer(TraceLayer::new_for_http());
错误处理
use axum::{Router, routing::get, response::IntoResponse, http::StatusCode};
async fn fallible_handler() -> Result<String, (StatusCode, &'static str)> {
Err((StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong"))
}
let app = Router::new().route("/error", get(fallible_handler));
静态文件服务
use axum::{Router, routing::get_service};
use tower_http::services::ServeDir;
let app = Router::new().nest_service(
"/static",
get_service(ServeDir::new("./static"))
);
路由嵌套
use axum::{Router, routing::get};
async fn api_v1_users() -> &'static str { "v1 users" }
async fn api_v2_users() -> &'static str { "v2 users" }
let api_v1 = Router::new().route("/users", get(api_v1_users));
let api_v2 = Router::new().route("/users", get(api_v2_users));
let app = Router::new()
.nest("/api/v1", api_v1)
.nest("/api/v2", api_v2);
异步数据库操作
use axum::{Router, routing::get, Extension};
use sqlx::postgres::PgPoolOptions;
async fn db_handler(Extension(pool): Extension<sqlx::PgPool>) -> String {
let row: (i64,) = sqlx::query_as("SELECT $1")
.bind(150_i64)
.fetch_one(&pool)
.await.unwrap();
format!("Result: {}", row.0)
}
#[tokio::main]
async fn main() {
let pool = PgPoolOptions::new()
.connect("postgres://user:pass@localhost/db")
.await.unwrap();
let app = Router::new()
.route("/db", get(db_handler))
.layer(Extension(pool));
}
WebSocket路由(axum)
use axum::{Router, routing::get, extract::ws::WebSocketUpgrade};
async fn ws_handler(ws: WebSocketUpgrade) -> impl IntoResponse {
ws.on_upgrade(|socket| async move {
// WebSocket处理逻辑
})
}
let app = Router::new().route("/ws", get(ws_handler));
JSON 请求与响应
JSON 响应处理
use actix_web::{get, App, HttpServer, Responder};
use serde::Serialize;
#[derive(Serialize)]
struct MyObj {
name: String,
age: u8,
}
#[get("/json")]
async fn json_response() -> impl Responder {
web::Json(MyObj {
name: "Alice".to_string(),
age: 30,
})
}
JSON 请求处理
use actix_web::{post, web, App, HttpServer, Responder};
use serde::Deserialize;
#[derive(Deserialize)]
struct Info {
username: String,
}
#[post("/submit")]
async fn submit(info: web::Json<Info>) -> impl Responder {
format!("Welcome {}!", info.username)
}
以下是基于Rust的JSON请求与响应处理的实用示例集合,涵盖常见场景和库(如serde
、reqwest
、actix-web
等)。示例按功能分类,每个示例独立可用。
基础序列化与反序列化
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct User {
id: u32,
name: String,
}
// 序列化结构体到JSON字符串
let user = User { id: 1, name: "Alice".to_string() };
let json_str = serde_json::to_string(&user).unwrap();
println!("Serialized: {}", json_str); // {"id":1,"name":"Alice"}
// 反序列化JSON字符串到结构体
let decoded_user: User = serde_json::from_str(&json_str).unwrap();
println!("Deserialized: {:?}", decoded_user);
使用reqwest发送GET请求
use reqwest::Error;
#[tokio::main]
async fn main() -> Result<(), Error> {
let response = reqwest::get("https://jsonplaceholder.typicode.com/posts/1")
.await?
.json::<serde_json::Value>()
.await?;
println!("Response: {:?}", response);
Ok(())
}
使用reqwest发送POST请求
#[derive(Serialize)]
struct Post {
title: String,
body: String,
userId: u32,
}
#[tokio::main]
async fn main() -> Result<(), Error> {
let new_post = Post {
title: "Test Title".to_string(),
body: "Test Body".to_string(),
userId: 1,
};
let client = reqwest::Client::new();
let res = client.post("https://jsonplaceholder.typicode.com/posts")
.json(&new_post)
.send()
.await?
.json::<serde_json::Value>()
.await?;
println!("Response: {:?}", res);
Ok(())
}
使用actix-web处理JSON请求
use actix_web::{web, App, HttpServer, Responder};
#[derive(Deserialize)]
struct Info {
username: String,
}
async fn greet(info: web::Json<Info>) -> impl Responder {
format!("Hello {}!", info.username)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().route("/greet", web::post().to(greet)))
.bind("127.0.0.1:8080")?
.run()
.await
}
处理嵌套JSON结构
#[derive(Serialize, Deserialize)]
struct Address {
street: String,
city: String,
}
#[derive(Serialize, Deserialize)]
struct Profile {
name: String,
age: u8,
address: Address,
}
let profile = Profile {
name: "Bob".to_string(),
age: 30,
address: Address {
street: "Main St".to_string(),
city: "Metropolis".to_string(),
},
};
let json = serde_json::to_string_pretty(&profile).unwrap();
println!("{}", json);
自定义字段名称
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Product {
product_id: u32,
product_name: String,
}
let product = Product {
product_id: 101,
product_name: "Laptop".to_string(),
};
let json = serde_json::to_string(&product).unwrap(); // {"productId":101,"productName":"Laptop"}
处理可选字段
#[derive(Serialize, Deserialize)]
struct Book {
title: String,
#[serde(skip_serializing_if = "Option::is_none")]
subtitle: Option<String>,
}
let book1 = Book { title: "Rust".to_string(), subtitle: None };
let json1 = serde_json::to_string(&book1).unwrap(); // {"title":"Rust"}
let book2 = Book { title: "Rust".to_string(), subtitle: Some("Advanced".to_string()) };
let json2 = serde_json::to_string(&book2).unwrap(); // {"title":"Rust","subtitle":"Advanced"}
使用Hyper客户端
use hyper::{Client, Body};
use hyper_tls::HttpsConnector;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let https = HttpsConnector::new();
let client = Client::builder().build::<_, Body>(https);
let uri = "https://jsonplaceholder.typicode.com/todos/1".parse()?;
let resp = client.get(uri).await?;
let body_bytes = hyper::body::to_bytes(resp.into_body()).await?;
let body_str = String::from_utf8(body_bytes.to_vec())?;
println!("Response: {}", body_str);
Ok(())
}
处理日期时间
use chrono::{DateTime, Utc};
#[derive(Serialize, Deserialize)]
struct Event {
name: String,
#[serde(with = "chrono::serde::ts_seconds")]
timestamp: DateTime<Utc>,
}
let event = Event {
name: "Conference".to_string(),
timestamp: Utc::now(),
};
let json = serde_json::to_string(&event).unwrap();
使用warp框架
use warp::Filter;
#[derive(Serialize, Deserialize)]
struct Message {
text: String,
}
let hello = warp::path("hello")
.and(warp::post())