Actix-Web应用状态管理

一、概述

Actix Web 提供了强大的应用状态管理机制,让你能够在整个应用范围内安全地共享数据。

‌核心状态管理方式‌:

应用状态会被同一作用域内的所有路由和资源共享,可以通过 web::Data<T> 提取器来访问,其中 T 代表状态数据的类型。

二、共享状态(App Data)

修改主代码 src/main.rs

use actix_web::{web,get,post, App, HttpResponse, HttpServer};
use std::sync::Mutex;
 
struct AppState {
    counter: Mutex<i32>,
    app_name: String,
}
 
#[get("/count")]
async fn get_count(data: web::Data<AppState>) -> HttpResponse {
    let count = data.counter.lock().unwrap();
    HttpResponse::Ok().json(serde_json::json!({
        "app": data.app_name,
        "count": *count
    }))
}
 
#[post("/increment")]
async fn increment(data: web::Data<AppState>) -> HttpResponse {
    let mut count = data.counter.lock().unwrap();
    *count += 1;
    HttpResponse::Ok().json(serde_json::json!({
        "new_count": *count
    }))
}
 
#[actix_web::main]
async fn main() -> std::io::Result<()> {
    env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
    log::info!("Starting HTTP server on http://127.0.0.1:8080");
    
    let app_state = web::Data::new(AppState {
        counter: Mutex::new(0),
        app_name: String::from("Actix-Web Demo"),
    });
    
    HttpServer::new(move || {
        App::new()
            .app_data(app_state.clone())
            .service(get_count)
            .service(increment)
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

测试运行,访问接口: http://127.0.0.1:8080/count

image

 使用postman调用post接口:http://127.0.0.1:8080/increment

image

三、数据库连接池

这里以mysql 8为例,来演示如何连接数据库。

数据库在阿里云上面,创建一个测试数据库

CREATE DATABASE rust_blog
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;

新建表users

CREATE TABLE `users` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

插入2条数据

INSERT INTO `rust_blog`.`users` (`id`, `username`, `password`, `email`, `create_time`) VALUES (1, 'Alice', 'e10adc3949ba59abbe56e057f20f883e', 'alice@example.com', '2025-11-26 18:24:22');
INSERT INTO `rust_blog`.`users` (`id`, `username`, `password`, `email`, `create_time`) VALUES (2, 'Bob', 'e10adc3949ba59abbe56e057f20f883e', 'bob@example.com', '2025-11-26 18:25:45');

注意:密码使用md5加密 

修改Cargo.toml,增加mysql模块

# 异步 MySQL 驱动,支持 8.x
sqlx = { version = "0.8", features = ["runtime-tokio-native-tls", "mysql"] }
dotenvy = "0.15"   # 读取 .env

项目根目录,新增文件.env

DATABASE_URL=mysql://root:123456@localhost:3306/rust_blog

注意:如果密码带有@符号,需要进行URL-encode编码

打开在线url编码器,链接:https://www.convertstring.com/zh_CN/EncodeDecode/UrlEncode

 修改主代码 src/main.rs

use actix_web::{web, App, HttpResponse, HttpServer};
use dotenvy::dotenv;
use sqlx::{mysql::MySqlPool, mysql::MySqlPoolOptions, FromRow};
use serde::Serialize;

#[derive(FromRow, Serialize)]
struct User {
    id: i64,        // MySQL 里 BIGINT 对应 i64
    username: String,
    email: String,
}

#[actix_web::get("/users")]
async fn get_users_from_db(pool: web::Data<MySqlPool>) -> HttpResponse {
    let users = sqlx::query_as::<_, User>("SELECT id, username, email FROM users")
        .fetch_all(pool.get_ref())
        .await;

    match users {
        Ok(users) => HttpResponse::Ok().json(users),
        Err(e) => HttpResponse::InternalServerError().json(serde_json::json!({
            "error": e.to_string()
        })),
    }
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    dotenv().ok();
    env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));

    // 建立连接池
    let db_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let pool = MySqlPoolOptions::new()
        .max_connections(5)
        .connect(&db_url)
        .await
        .expect("Failed to create MySqlPool");

    HttpServer::new(move || {
        App::new()
            .app_data(web::Data::new(pool.clone()))
            .service(get_users_from_db)
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

注意:这里设置的连接池大小为5,生产环境,请根据实际情况修改。

重新运行,访问:http://127.0.0.1:8080/users

显示2条用户信息

image

本文参考链接:https://blog.youkuaiyun.com/sinat_41617212/article/details/154069236

Actix-web 是一个高效且灵活的 Rust Web 框架,其设计基于 Actor 模型,使得它在处理高并发场景时表现出色。该框架以其高性能、可扩展性和异步编程模型而闻名[^3]。通过 Actor 模型,每个 Actor 是一个独立的对象,负责处理自己的状态和行为,通过消息传递的方式,Actors 之间可以高效地进行通信。 在使用 Actix-web 时,可以借助中文使用指南来更轻松地理解和应用该框架,特别是对于偏好中文阅读的开发者而言非常有帮助。Actix-web 3.0 的中文文档翻译版本不仅忠实于原始英文文档的内容,还在示例和解释上进行了调整,确保它们适用于实际编码场景。此外,它还提供了可运行的 demo 示例和对关键概念的深入讲解,适合不同层次的 Rust 和 Actix-web 开发者[^2]。 Actix-web 的一大亮点是其灵活的架构,支持多种应用场景,从简单的 Web 服务到复杂的微服务架构[^3]。为了进一步增强其功能,Actix-web 支持中间件机制,方便地扩展功能,如日志记录、身份验证等。例如,tracing-actix-web 就是一个专为 Actix-Web 设计的中间件库,旨在收集和记录应用程序运行时的详细诊断数据。通过它,开发者可以轻松地对基于 Actix-Web 构建的应用进行结构化的追踪,从而极大地增强了系统的可观察性和调试效率[^1]。 此外,tracing-actix-web 集成 tracing 生态系统,以提供结构化的日志追踪功能。通过此库,开发者可以轻松地在处理 HTTP 请求时捕获详细的诊断信息,这对于性能分析、错误调试及服务监控至关重要。tracing-actix-web 支持自定义配置,并且能够与 OpenTelemetry 等流行追踪系统无缝对接,旨在成为 Actix-Web 应用中日志追踪的标准解决方案[^5]。 在开发 Web 应用时,用户认证是一个常见的需求。为了保护 API 端点,通常会在每个请求处理器中添加认证逻辑。但这样做会导致代码重复,并使得维护变得更加困难。因此,可以使用 actix-web 构建中间件来解决这个问题,这样不仅可以减少代码重复,还能提高代码的可维护性[^4]。 ### Actix-web 的使用 为了快速启动一个 Actix-web 项目,可以参考官方文档或者中文文档中的快速启动指南。通常,创建一个新的 Actix-web 项目涉及以下几个步骤: 1. 创建一个新的 Rust 项目。 2. 添加 Actix-web 作为依赖。 3. 编写一个简单的 Web 服务。 以下是一个简单的 Actix-web 服务示例: ```rust use actix_web::{web, App, HttpServer, Responder}; async fn index() -> impl Responder { "Hello, world!" } #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .route("/", web::get().to(index)) }) .bind("127.0.0.1:8080")? .run() .await } ``` 在这个例子中,我们创建了一个简单的 Web 服务器,它监听 `127.0.0.1:8080` 地址,并在根路径 `/` 上响应 "Hello, world!" 消息。 ### Actix-web 的最新动态 Actix-web 社区活跃,不断有新的特性和改进被加入到框架中。例如,对于 tracing-actix-web 这样的中间件库,它随着社区对可观测性的重视而不断发展,支持与 OpenTelemetry 等流行追踪系统的集成,为开发者提供了更多的选择和灵活性。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值