0Pricing
Learn Rust Coding · 课时

使用 Actix-web/Rocket 构建 REST API

使用 Actix-web 或 Rocket 等现代 Rust Web 框架开发 RESTful API,处理路由、请求和响应。

使用 Actix-web/Rocket 构建 REST API 是 CoddyKit 上的免费 Learn Rust Coding 课时。 这是第 1 节课,共 3 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Learn Rust Coding 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Learn Rust Coding 课程共包含 3 节课。

什么是 REST API?

REST,即 RE 表述性状态转移,是一种用于网络应用的架构风格。它定义了一组原则,用于规定 Web 服务应如何进行通信。

您可以将其理解为一组构建 Web 服务的指导原则:服务应当无状态、可缓存,并使用标准 HTTP 方法与资源进行交互。

  • 资源:任何可以命名的对象,例如用户、产品或订单。
  • URI:资源的唯一标识符(例如 /users/123)。
  • HTTP 方法:对资源执行的标准操作(GET、POST、PUT、DELETE)。

为什么选择 Rust 构建 Web 服务?

Rust 为 Web 服务开发带来了独特优势,因此非常适合构建高性能且可靠的 API:

  • 性能:Rust 的零成本抽象意味着代码非常高效,通常可以达到与 C/C++ 相当的水平。
  • 内存安全:所有权系统可以防止空指针解引用和数据竞争等常见错误,从而带来更加稳健的服务。
  • 并发:Rust 的 async/await 模型结合其安全保证,使构建并发 Web 服务变得更加安心。
  • 可靠性:强大的类型系统和编译时检查可以尽早发现许多错误。

认识 Actix-web

在 Rust 中构建 Web 服务时,我们通常会使用框架。Actix-web 是一个功能强大、实用且速度极快的 Rust Web 框架。

它构建于 Actix(一个参与者框架)之上,但要有效使用 Actix-web,您不需要理解参与者。它专为异步操作而设计,非常适合处理大量并发 API 请求等受 I/O 限制的任务。

Actix-web 提供了路由、请求与响应处理、中间件等多种工具,大大简化了复杂 API 的创建过程。

项目设置与依赖项

首先,我们将创建一个新的 Rust 项目,并添加必要的依赖项。我们将使用 actix-web 作为框架,使用 serde 对 JSON 数据进行序列化和反序列化。

首先,创建一个新项目:

cargo new my_rest_api --bin

然后,将以下几行添加到 Cargo.toml 文件的 [dependencies] 部分:

[dependencies]
actix-web = "4"
serde = { version = "1.0", features = ["derive"] }

您的第一个 Actix-web 服务器

让我们编写一个最小化的 Actix-web 服务器。这段代码会建立基本结构,以监听 8080 端口上的传入 HTTP 请求。它目前还不会处理任何特定路由,但这是后续开发的基础。

#[actix_web::main] 宏会使我们的 async fn main 与 Actix-web 的运行时兼容。

use actix_web::{App, HttpServer};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    println!("Server running at http://127.0.0.1:8080");
    HttpServer::new(|| {
        // Our application instance, where we'll add routes
        App::new()
    })
    .bind(("127.0.0.1", 8080))? // Bind to an IP address and port
    .run() // Start the server
    .await // Await its completion
}

定义 GET 路由

现在,让我们为服务器添加一个简单的路由。路由会将传入的 HTTP 请求路径和方法(例如 GET /hello)映射到特定的处理函数。

我们的处理函数 hello_world 只会返回一个字符串。web::get().to() 会将此处理函数注册为处理发往 /hello 路径的 GET 请求。

use actix_web::{web, App, HttpServer, Responder};

// A handler function that returns a simple string response
async fn hello_world() -> impl Responder {
    "Hello, Actix-web!"
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    println!("Server running at http://127.0.0.1:8080");
    HttpServer::new(|| {
        App::new()
            // Register our route: GET /hello maps to hello_world()
            .route("/hello", web::get().to(hello_world))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

用于动态路由的路径参数

API 通常需要处理 URL 中的动态部分,例如 ID 或名称。Actix-web 使用路径参数来捕获这些值。

我们在路由中定义一个占位符(例如 /{name})。在处理函数中,我们使用 web::Path<String>(或任何可以反序列化的其他类型)来提取该值。

use actix_web::{web, App, HttpServer, Responder};

// Handler function with a path parameter 'name'
async fn greet_name(name: web::Path<String>) -> impl Responder {
    format!("Hello, {}!", name.into_inner())
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    println!("Server running at http://127.0.0.1:8080");
    HttpServer::new(|| {
        App::new()
            // Route with a dynamic path segment for a name
            .route("/greet/{name}", web::get().to(greet_name))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

处理 POST 请求与 JSON

创建或更新资源时,我们使用 POST 或 PUT 请求,并通常将数据以 JSON 形式放在请求正文中发送。

使用 web::Json<T> 可以轻松处理 JSON。我们定义一个与预期 JSON 结构相匹配的 Rust struct,从 serde 派生 Deserialize,Actix-web 就会自动将传入的 JSON 解析为我们的结构体。

use actix_web::{web, App, HttpServer, Responder};
use serde::{Deserialize, Serialize};

// Define a struct to represent our incoming JSON data
#[derive(Deserialize, Serialize)]
struct User {
    username: String,
    email: String,
}

// Handler for POST requests that accepts a JSON User object
async fn create_user(user: web::Json<User>) -> impl Responder {
    // In a real app, you'd save this user to a database
    format!("User created: {} ({})", user.username, user.email)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    println!("Server running at http://127.0.0.1:8080");
    HttpServer::new(|| {
        App::new()
            // POST /users expects a JSON body and maps to create_user()
            .route("/users", web::post().to(create_user))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

使用状态构建简单 API

让我们结合所学内容,构建一个在内存中管理用户列表的小型 API。我们将使用 web::Data,在各个处理函数之间共享特定于应用程序的状态(即用户列表)。

std::sync::Mutex 用于确保多个并发请求能够安全地访问和修改我们的 Vec<User>。我们将提供 GET /users 和 POST /users 端点。

use actix_web::{web, App, HttpServer, Responder, HttpResponse};
use serde::{Deserialize, Serialize};
use std::sync::Mutex; // For shared mutable state

// Define a User struct that can be serialized/deserialized and cloned
#[derive(Deserialize, Serialize, Clone)]
struct User {
    id: u32,
    username: String,
    email: String,
}

// Application state to hold our users and track next ID
struct AppState {
    users: Mutex<Vec<User>>,
    next_id: Mutex<u32>,
}

// Handler to get all users
async fn get_users(data: web::Data<AppState>) -> impl Responder {
    let users = data.users.lock().unwrap(); // Acquire a lock
    web::Json(users.clone()) // Return users as JSON
}

// Handler to create a new user
async fn create_user(
    data: web::Data<AppState>,
    new_user: web::Json<User>,
) -> impl Responder {
    let mut users = data.users.lock().unwrap();
    let mut next_id = data.next_id.lock().unwrap();

    let user = User {
        id: *next_id,
        username: new_user.username.clone(),
        email: new_user.email.clone(),
    };
    users.push(user.clone());
    *next_id += 1; // Increment for the next user
    HttpResponse::Created().json(user) // Return 201 Created status and user
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    println!("Server running at http://127.0.0.1:8080");
    // Create shared application state
    let app_state = web::Data::new(AppState {
        users: Mutex::new(vec![]), // Initialize with an empty user list
        next_id: Mutex::new(1),    // Start IDs from 1
    });

    HttpServer::new(move || { // 'move' closure to capture app_state
        App::new()
            .app_data(app_state.clone()) // Register shared state with the app
            .route("/users", web::get().to(get_users))
            .route("/users", web::post().to(create_user))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

API 概念快速检查

您已经学会了如何设置基本的 Actix-web 服务器,以及如何处理不同的 HTTP 请求。让我们 test 一下您的理解!

回顾与后续步骤

做得很好!您已经迈出了使用 Rust 和 Actix-web 构建 RESTful API 的第一步。

  • 我们探讨了 REST API 的基础知识,以及 Rust 为什么非常适合这一领域。
  • 您学会了如何设置基本的 Actix-web 项目。
  • 我们介绍了如何定义 GET 和 POST 路由。
  • 您了解了如何提取路径参数并处理 JSON 负载。
  • 最后,您使用 web::Data 构建了一个管理内存状态的简单 API。

接下来,您将深入学习数据库集成和稳健的错误处理,以构建更强大、更适合投入生产的 Web 服务!

常见问题解答

「使用 Actix-web/Rocket 构建 REST API」课时是免费的吗?

是的 — 「使用 Actix-web/Rocket 构建 REST API」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Learn Rust Coding 课程的其余内容,请升级到 CoddyKit PRO。 Learn Rust Coding 课程共包含 3 节课。

「使用 Actix-web/Rocket 构建 REST API」这节课中我会学到什么?

使用 Actix-web 或 Rocket 等现代 Rust Web 框架开发 RESTful API,处理路由、请求和响应。 你通过在浏览器中直接运行的动手代码来练习 Learn Rust Coding,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Learn Rust Coding 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Learn Rust Coding 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 3 节。

「使用 Actix-web/Rocket 构建 REST API」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Learn Rust Coding 课中编写并运行代码吗?

能。每节 Learn Rust Coding 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用 Actix-web/Rocket 构建 REST API
  2. 数据库集成(SQLx/Diesel)
  3. 身份验证与授权
← 返回 Learn Rust Coding