当前位置: 首页 > news >正文

使用 Actix Web 构建 Web 应用

使用 Actix Web 构建 Web 应用

1. 添加依赖

首先,在 Cargo.toml 中添加 actix-web 和 tokio 依赖:

[dependencies]
actix-web = "4.11.0"
tokio = { version = "1.47.1", features = ["macros", "rt-multi-thread"] }

说明:

  • actix-web 是 Rust 中高性能的异步 Web 框架。
  • tokio 提供异步运行时,rt-multi-thread 启用多线程执行器,macros 支持 #[tokio::main] 等宏。

2. 编写一个简单的 Web 服务

use actix_web::{App, HttpRequest, HttpServer, Responder, web};async fn greet(req: HttpRequest) -> impl Responder {let name = req.match_info().get("name").unwrap_or("world");format!("Hello {}!", name)
}#[tokio::main]
async fn main() -> std::io::Result<()> {HttpServer::new(|| {App::new().route("/", web::get().to(greet)).route("/{name}", web::get().to(greet))}).bind("127.0.0.1:8000")?.run().await
}

该程序启动一个监听 127.0.0.1:8000 的 HTTP 服务器:

  • 访问 http://127.0.0.1:8000/ 返回 Hello world!
  • 访问 http://127.0.0.1:8000/Alice 返回 Hello Alice!

3. Actix Web 应用程序核心组件解析

3.1 HttpServer:传输层的入口

HttpServer 负责处理底层网络通信,是整个应用的“门面”。其主要职责包括:

  • 监听地址配置: 绑定 TCP 地址(如 127.0.0.1:8000)或 Unix 域套接字;
  • 连接管理:控制最大并发连接数、连接速率等;
  • 传输安全: 支持通过 TLS(如 rustls 或 openssl)启用 HTTPS。

关键点: HttpServer 不处理业务逻辑,仅负责接收连接并将其交给上层应用。

3.2 App:应用逻辑的容器
当 HttpServer 接收到新连接后,请求会被交由 App 处理。App 是业务逻辑的核心载体,包含:

  • 路由(Routes):定义 URL 路径与处理函数的映射;
  • 中间件(Middleware): 用于日志、认证、错误处理等横切关注点;
  • 服务配置: 如状态共享、数据注入等。
    示例中的 App 配置如下:
App::new().route("/", web::get().to(greet)).route("/{name}", web::get().to(greet))
  • App::new() 创建一个空的应用实例;
  • .route(path, handler) 采用链式调用方式注册多个端点。

3.3 路由(Route)与处理器(Handler)

路由的组成

每个 .route() 调用包含两个要素:

  • 路径(Path)
    • 静态路径:如 “/”
    • 动态模板:如 “/{name}”,其中 {name} 是路径参数。
  • 路由守卫(Guard) + 处理器(Handler)
    • web::get()Route::new().guard(guard::Get()) 的简写,表示仅匹配 GET 请求
    • 守卫(Guard)是一组条件(如 HTTP 方法、Header 等),只有全部满足时才会调用处理器。

匹配机制:

当请求到达时,Actix Web 会按注册顺序遍历所有路由,第一个同时满足路径模板和守卫条件的路由将被选中,并调用其处理器。

处理器函数签名

处理器是一个异步函数,其典型签名如下:

async fn greet(req: HttpRequest) -> impl Responder {let name = req.match_info().get("name").unwrap_or("world");format!("Hello {}!", name)
}

扩展性:你可以为自定义类型实现 Responder,从而直接返回结构化响应(如 JSON 对象)

4. #[tokio::main] 的作用详解

在 Rust 中,#[tokio::main] 是一个非常常见但又容易被忽略的过程宏。它看似只是让 main 函数能使用 async,但背后其实做了很多底层工作。

4.1 为什么需要异步 main 函数?

我们通常希望在异步环境中运行程序的入口函数,例如:

#[tokio::main]
async fn main() {HttpServer::new(|| App::new().route("/", web::get().to(greet))).bind("127.0.0.1:8000").unwrap().run().await.unwrap();
}

这里的 HttpServer::run() 是一个 异步方法,而在 Rust 中,只能在异步函数中调用异步函数。
这就意味着 main 也必须是异步的。

但问题是:

Rust 的 main 函数不能直接是异步的。

为什么?这要从 Rust 的异步机制说起。

4.2 Rust 异步编程的底层原理

Rust 的异步编程基于 Future trait。
Future 代表一个可能尚未完成的计算,它通过一个 poll 方法逐步推进执行。

换句话说,Rust 的 Future 是惰性的:
除非有外部“驱动者”调用 poll,它不会自动执行。这种机制称为 “被动型(pull)” 异步模型。

Rust 本身虽然支持 async 语法,但并没有内置异步运行时(runtime)。
这意味着:

  • 编译器能帮你生成 Future

  • 但不会帮你驱动它执行。

4.3 谁来执行 Future

既然 Rust 没有内置运行时,那就需要你在项目中引入一个异步运行时(runtime)库,比如:

[dependencies]
tokio = { version = "1", features = ["full"] }

Tokio 就是最常用的异步运行时之一。它负责:

  • 启动多线程调度器;

  • 管理任务执行;

  • 驱动 Futurepoll

  • 提供异步 IO、定时器等功能。

4.4 main 为何不能直接是异步的?

main 函数是程序的入口点,操作系统只会调用一个普通的同步函数 fn main().
而异步函数返回的是一个 Future 对象,不会自动运行。

因此编译器并不知道:
“谁应该来执行这个 Future(也就是谁负责调用 poll)?”

Rust 没有规定运行时标准接口,所以这就需要我们自己来启动一个运行时,然后在其中运行异步任务。

4.5 #[tokio::main] 到底做了什么?

你可能已经猜到了:
#[tokio::main] 的作用就是——
在 main 函数中自动创建并启动一个 Tokio 运行时,然后在其中执行你的异步逻辑。

为了验证这一点,我们可以使用工具 cargo-expand 展开宏:

cargo install cargo-expand
cargo expand

运行后你会看到类似的展开结果:

fn main() -> std::io::Result<()> {let body = async {HttpServer::new(|| {App::new().route("/", web::get().to(greet)).route("/{name}", web::get().to(greet))}).bind("127.0.0.1:8000")?.run().await};tokio::runtime::Builder::new_multi_thread().enable_all().build().expect("Failed building the Runtime").block_on(body)
}

可以看到:

  • 展开后 main 变成了一个普通同步函数;

  • 宏自动生成了一个 Tokio 运行时;

  • block_on(body) 来驱动异步代码执行。

这就解释了为什么 #[tokio::main] 能“让异步的 main 函数编译通过”——
其实它只是帮你包了一层运行时初始化代码。

5. 实现健康检查处理器(Health Check Handler)

在 Web 服务中,健康检查(health check) 通常用于验证服务器是否处于可用状态。
当客户端向 /health_check 发送 GET 请求时,服务器应返回 状态码 200,且无响应体。

5.1 编写健康检查处理器

我们首先创建一个异步请求处理函数。参考之前的 greet 函数,先定义如下:

async fn health_check(req: HttpRequest) -> impl Responder {todo!()
}

这里的 req 表示传入的 HTTP 请求对象。
不过在健康检查中,我们并不需要使用任何请求信息,因此该参数其实是多余的。

5.2 构建响应对象

由于 HttpResponse 类型实现了 Responder trait,我们可以直接返回一个 HttpResponse。

HttpResponse::Ok() 会返回一个以 200 OK 为状态码的 HttpResponseBuilder
我们可以调用 .finish() 来构建一个无响应体的 HttpResponse

async fn health_check() -> impl Responder {HttpResponse::Ok().finish()
}

说明
HttpResponseBuilder 本身也实现了 Responder trait
因此即使不调用 .finish() 也能正常工作。
不过,为了语义更明确、风格一致,推荐保留 .finish()

5.3 注册路由

接下来,我们在应用中将 /health_check 路由与刚定义的处理器绑定:

App::new().route("/health_check", web::get().to(health_check))

这样,当客户端访问 /health_check 时,服务器就会返回:

HTTP/1.1 200 OK
Content-Length: 0

5.4 最终代码示例

use actix_web::{web, App, HttpResponse, HttpServer, Responder};async fn health_check() -> impl Responder {HttpResponse::Ok().finish()
}#[actix_web::main]
async fn main() -> std::io::Result<()> {HttpServer::new(|| {App::new().route("/health_check", web::get().to(health_check))}).bind("127.0.0.1:8000")?.run().await
}

运行后,访问 http://127.0.0.1:8000/health_check即可看到一个返回 200 OK 且无响应体的健康检查接口
在这里插入图片描述

http://www.dtcms.com/a/477502.html

相关文章:

  • Rust开发环境搭建
  • MFC中一个类的成员变量值自动被篡改:多重继承带来的问题
  • 潘家园网站建设wordpress 虚拟主
  • 【第五章:计算机视觉-计算机视觉在工业制造领域中的应用】1.工业缺陷分割-(1)工业品缺陷风格基础知识:割任务定义、数据集介绍
  • Redis除了做缓存还能用来干什么
  • 【Frida Android】基础篇4:Java层Hook基础——调用静态方法
  • 中国建筑网官网图片深圳网站排名优化团队
  • Vue3+Three.js实现3D模型加载与动画(实践:官方的一个样例)
  • mac maven 安装
  • 体验GPT-OSS-120B:在PH8平台上探索超大规模语言模型的强大能力
  • Spark和Flink差异
  • 怎么做网站广告赚钱专业网站设计团队
  • 网站建设这块是怎么挣钱的网站服务器买了后怎么做
  • 从注册到养号,Walmart鲲鹏系统打造完整运营链路
  • 云服务器安装JDK、Tomcat、MySQL
  • 科创企业品牌营销顾问:助力企业腾飞的关键角色
  • 怎样解读黑格尔的客观唯心主义
  • 5-2〔OSCP ◈ 研记〕❘ SQL注入攻击▸MySQL MSSQL基础
  • 电话交换机IPPBX的数据存储在AWS亚马逊云
  • 公共数据开放网站建设怎样做app
  • 嵌入式学习linux内核驱动8——IIC设备驱动和lm75-dht11
  • 经典机器学习深度学习领域数据集介绍
  • 个人网站怎么做才能值钱优设网页设计
  • 【Unity】MMORPG游戏开发(一)身份认证
  • 竞价网站与竞价网站之间做友情链接建邺区住房 建设 网站
  • Django视图与路由全解析:从URL到页面,一篇讲透
  • 推荐系统实战:python新能源汽车智能推荐(两种协同过滤+Django 全栈项目 源码)计算机专业✅
  • 数据结构二叉树——层序遍历 扩展二叉树的左视图
  • .NET Core + Nginx服务器零基础部署全流程(附资源)
  • 吴江区经济开发区规建设局网站手机app如何开发制作