您当前的位置:首页 > 电脑百科 > 程序开发 > 架构

你应该知晓的 Rust Web 框架

时间:2023-12-07 14:29:53  来源:微信公众号  作者:前端柒八九

前言

在之前的用 Rust 搭建 React Server Components 的 Web 服务器我们利用了Axum构建了RSC的服务器。也算是用Rust在构建Web服务上的小试牛刀。

虽然说Axum在Rust Web应用中一枝独秀。但是,市面上也有很多不同的解决方案。所以,今天我们就比较一些 Rust 框架,突出它们各自的优势和缺点,以帮助我们为项目做出明智的决策。没有对比就没有选择,我们只有在真正的了解各个框架的优缺点和适应场景,在以后的开发中才能有的放矢的放心选择。

文本中,我们会介绍很多Rust框架。并且会按照如下的受欢迎程度的顺序来讲。

你应该知晓的 Rust Web 框架

好了,天不早了,干点正事哇。

我们能所学到的知识点

  1. Axum
  2. Actix Web
  3. Rocket
  4. Warp
  5. Tide
  6. Poem

1. Axum

Axum[1] 是 Rust 生态系统中具有特殊地位的 Web 应用程序框架(从下载量就可见端倪)。它是 Tokio 项目[2]的一部分,Tokio 是使用 Rust 编写「异步网络应用程序的运行时」。Axum 不仅使用 Tokio 作为其异步运行时,还与 Tokio 生态系统的其他库集成,利用 Hyper[3] 作为其 HTTP 服务器和 Tower[4] 作为中间件。通过这样做,我们能够重用 Tokio 生态系统中现有的库和工具。

Axum 「不依赖于宏」,而是利用 Rust 的类型系统提供安全且人性化的 API。这是通过使用特性来定义框架的核心抽象实现的,例如 Handler 特性,用于「定义应用程序的核心逻辑」。这种方法允许我们轻松地「从较小的组件中组合应用程序」,这些组件可以在多个应用程序中重用。

在 Axum 中,处理程序(handler)是一个「接受请求并返回响应」的函数。这与其他后端框架类似,但使用 Axum 的 FromRequest 特性,我们可以指定从请求中提取的数据类型。返回类型需要实现 IntoResponse 特性(trAIt),已经有许多类型实现了这个特性,包括允许轻松更改响应的状态代码的元组类型。

Rust 的类型系统、泛型,尤其是在traits中使用异步方法(或更具体地说是返回的 Future),当不满足trait限制时,Rust 的错误消息会很复杂。特别是当尝试匹配抽象trait限制时,经常会得到一堆难以解读的文本。为此Axum 提供了一个带有辅助宏的库,将错误放到实际发生错误的地方,使得更容易理解发生了什么错误。

虽然Axum 做了很多正确的事情,可以很容易地启动执行许多任务的应用程序。但是,有一些事情需要特别注意。Axum版本仍然低于 1.0,也就意味着Axum 团队保留在版本之间「根本性地更改 API 的自由」,这可能导致我们的应用程序出现严重问题。

Axum 示例

下面展示了一个 WebSocket 处理程序,它会回显收到的任何消息。

// #[tokio::main] 宏标记了 `main` 函数,表明这是一个异步的`Tokio`应用程序。
#[tokio::main]
async fn main() {
    // 首先创建了一个 `TcpListener` 监听器,绑定到地址 "127.0.0.1:3000" 上
    // 然后,通过 `await` 等待监听器绑定完成
    // 如果绑定失败,会通过 `unwrap` 方法抛出错误。
    let listener = tokio:.NET::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();
    println!("listening on {}", listener.local_addr().unwrap());
    // 使用 `axum::serve` 启动 Axum 框架的服务器,
    //    监听前面创建的 `TcpListener`。
    // `App()` 函数返回的是一个 `Router`
    //    它定义了一个简单的路由,将路径 "/a" 映射到处理函数 `a_handler`。
    axum::serve(listener, app()).await.unwrap();
}

// 返回一个 `Router`,它只有一个路由规则,
//    将 "/a" 路径映射到 `a_handler` 处理函数
fn app() -> Router {
    Router::new()
        .route("/a", get(a_handler))
}

// 一个WebSocket处理程序,它会回显收到的任何消息。
// 定义为一个WebSocket处理程序,
//   它接收一个 `WebSocketUpgrade` 参数,表示WebSocket升级。
async fn a_handler(ws: WebSocketUpgrade) -> Response {
    // 调用将WebSocket升级后的对象传递给 `a_handle_socket` 处理函数。
    ws.on_upgrade(a_handle_socket)
}

async fn a_handle_socket(mut socket: WebSocket) {
    // 使用 while let 循环,持续从 WebSocket 连接中接收消息。 
    // socket.recv().await 通过异步的方式接收消息,返回一个 Result,
    // 其中 Ok(msg) 表示成功接收到消息。
    while let Some(Ok(msg)) = socket.recv().await {
        //  使用 if let 匹配,判断接收到的消息是否为文本消息。
        //  WebSocket消息可以是不同类型的,这里我们只处理文本消息。
        if let Message::Text(msg) = msg {
            // 构造一个回显消息,将客户端发送的消息包含在回显消息中。
            // 然后,使用 socket.send 方法将回显消息发送回客户端。
            // await 等待发送操作完成。
            if socket
                .send(Message::Text(format!("You said: {msg}")))
                .await
                // 检查 send 操作是否返回错误。
                // 如果发送消息出现错误(例如,连接断开),
                // 就通过 break 跳出循环,结束处理函数。
                .is_err()
            {
                break;
            }
        }
    }
}

Axum 特点

  • 无宏 API。
  • 利用 Tokio、Tower 和 Hyper 构建强大的生态系统。
  • 出色的开发体验。
  • 仍处于 0.x 版本,因此可能发生重大变更。

2. Actix Web

Actix Web[5] 是 Rust 中存在已久且非常受欢迎的 Web 框架之一。像任何良好的开源项目一样,它经历了许多迭代,但已经达到了主要版本(不再是 0.x),换句话说:在主要版本内,它可以确保没有破坏性的更改。

乍一看,Actix Web 与 Rust 中的其他 Web 框架非常相似。我们使用宏来定义 HTTP 方法和路由(类似于 Rocket),并使用提取器(extractors)从请求中获取数据(类似于 Axum)。与 Axum 相比,它们之间的相似之处显著,甚至在它们命名概念和特性的方式上也很相似。最大的区别是 Actix Web 没有将自己与Tokio 生态系统强关联在一起。虽然 Tokio 仍然是 Actix Web 底层的运行时,但是该框架具有自己的抽象和特性,以及自己的一套 crates 生态系统。这既有利有弊。一方面,我们可以确保事物能够很好地配合使用,另一方面,我们可能会错失 Tokio 生态系统中已经可用的许多功能。

Actix Web 实现了自己的 Service 特性,它基本上与 Tower 的 Service 相同,但仍然不兼容。这意味着在 Tower 生态系统中大多数可用的中间件在 Actix 中不可用。

如果在 Actix Web 中需要实现一些特殊任务,而需要自己实现,我们可能会碰到运行框架中的 Actor 模型。这可能会增加一些意想不到的问题。

但 Actix Web 社区很给力。该框架支持 HTTP/2 和 WebSocket 升级,提供了用于 Web 框架中最常见任务的 crates 和指南,以及出色的文档,而且速度很快。Actix Web 之所以受欢迎,是有原因的,「如果我们需要保证版本,请注意它可能是我们目前的最佳选择」。

Actix Web 示例

在 Actix Web 中,一个简单的 WebSocket 回显服务器如下所示:

use actix::{Actor, StreamHandler};
use actix_web::{
  web, 
  App, 
  Error, 
  HttpRequest, 
  HttpResponse, 
  HttpServer
};
use actix_web_actors::ws;

/// 定义HTTP Actor
// 定义了一个名为 MyWs 的结构体,这将用作WebSocket的Actix Actor。
// Actors 是Actix框架中的并发单元,用于处理异步消息
struct MyWs;

// 为 MyWs 结构体实现了 Actor trait,指定了 WebsocketContext 作为上下文类型。
impl Actor for MyWs {
    type Context = ws::WebsocketContext<Self>;
}

/// 处理ws::Message消息的处理程序
// 为 MyWs 结构体实现了 StreamHandler trait,处理WebSocket连接中的消息。
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for MyWs {
    // 对接收到的不同类型的消息进行处理。例如,对于 Ping 消息,发送 Pong 消息作为响应。
    fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
        match msg {
            Ok(ws::Message::Ping(msg)) => ctx.pong(&msg),
            Ok(ws::Message::Text(text)) => ctx.text(text),
            Ok(ws::Message::Binary(bin)) => ctx.binary(bin),
            _ => (),
        }
    }
}

// 定义了一个处理HTTP请求的异步函数。
async fn index(req: HttpRequest, stream: web::Payload) -> Result<HttpResponse, Error> {
    // 将WebSocket连接升级,并将请求委托给 MyWs Actor 处理。
    let resp = ws::start(MyWs {}, &req, stream);
    println!("{:?}", resp);
    resp
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    //  创建了一个 HttpServer 实例,通过 App::new() 创建一个应用,
    // 该应用只有一个路由,将路径 "/ws/" 映射到处理函数 index 上。
    HttpServer::new(|| App::new().route("/ws/", web::get().to(index)))
        // 绑定服务器到地址 "127.0.0.1" 和端口 8080。
        .bind(("127.0.0.1", 8080))?
        // 启动服务器并等待其完成运行。
        .run()
        .await
}

Actix Web 特点

  • 拥有强大的生态系统。
  • 基于 Actor 模型。
  • 通过主要版本保证的稳定 API。
  • 出色的文档。

3. Rocket

Rocket[6] 在 Rust Web 框架生态系统中已经有一段时间了:它的主要特点是基于宏的路由、内置表单处理、对数据库和状态管理的支持,以及其自己版本的模板!Rocket 确实尽力做到构建 一个 Web 应用程序所需的一切。

然而,Rocket 的雄心壮志也带来了一些代价。尽管仍在积极开发中,但发布的频率不如以前。这意味着框架的用户会错过许多重要的东西。

此外,由于其一体化的方法,我们还需要了解 Rocket 的实现方式。Rocket 应用程序有一个「生命周期」,构建块以特定的方式连接,如果出现问题,我们需要理解问题出在哪里。

Rocket 是一个很棒的框架,如果我们想开始使用 Rust 进行 Web 开发,它是一个很好的选择。「对于我们许多人来说,Rocket 是进入 Rust 的第一步」,使用它仍然很有趣。

Rocket 示例

处理表单的 Rocket 应用程序的简化示例:

// 定义了一个名为 Password 的结构体,该结构体派生了 Debug 和 FromForm traits。
// FromForm trait 用于从表单数据中提取数据。
// 该结构体包含两个字段 first 和 second,分别表示密码的第一个和第二个部分。
#[derive(Debug, FromForm)]
struct Password<'v> {
    // 表示对字段的长度进行了验证,要求长度在6个字符以上
    #[field(validate = len(6..))]
    // 表示第一个字段必须等于第二个字段
    #[field(validate = eq(self.second))]
    first: &'v str,
    //  表示第二个字段必须等于第一个字段。
    #[field(validate = eq(self.first))]
    second: &'v str,
}

// 省略其他结构体和实现...

// 定义了一个处理GET请求的函数 index,返回一个 Template 对象。
// 这个函数用于渲染首页。
#[get("/")]
fn index() -> Template {
    Template::render("index", &Context::default())
}

// 定义了一个处理POST请求的函数 submit。
// 这个函数接受一个 Form 对象,其中包含了表单的数据
#[post("/", data = "<form>")]
fn submit(form: Form<Submit<'_>>) -> (Status, Template) {
    // 通过检查 form.value 是否包含 Some(ref submission) 来判断表单是否提交。
    let template = match form.value {
        // 如果提交了表单,打印提交的内容,并渲染 "success" 页面;
        Some(ref submission) => {
            println!("submission: {:#?}", submission);
            Template::render("success", &form.context)
        }
        // 否则,渲染 "index" 页面。
        None => Template::render("index", &form.context),
    };

    (form.context.status(), template)
}

// 定义了启动Rocket应用程序的函数。
#[launch]
fn rocket() -> _ {
    // 使用 rocket::build() 创建一个Rocket应用程序实例
    rocket::build()
        // 并通过 .mount() 方法挂载路由。
        // routes![index, submit] 定义了两个路由,
        // 分别映射到 index 和 submit 函数。
        .mount("/", routes![index, submit])
        // 添加了一个模板处理的Fairing(Rocket中的中间件)
        .attach(Template::fairing())
        // 将静态文件服务挂载到根路径。
        .mount("/", FileServer::from(relative!("/static")))
}

Rocket 特点

  • 一体化的方法。
  • 出色的开发体验。
  • 开发活跃度不如以前。
  • 初学者的绝佳选择。

4. Warp

Warp[7] 是一个构建在 Tokio 之上的 Web 框架,而且是一个非常好的框架。它与我们之前看到的其他框架非常不同。

Warp 与 Axum 有一些共同的特点:它构建在 Tokio 和 Hyper 之上,并利用了 Tower 中间件。然而,它在方法上有很大的不同。Warp 是建立在 Filter trait 之上的。

在 Warp 中,我们构建一系列应用于传入请求的过滤器,并将请求传递到管道直到达到末端。过滤器可以链接,它们可以组合。这使我们能够构建非常复杂的管道,但仍然易于理解。

Warp 也比 Axum 更接近 Tokio 生态系统,这意味着我们可能会在没有任何粘合特性的情况下处理更多 Tokio 结构和概念。

Warp 采用非常功能化的方法,如果这是我们的编程风格,我们将喜欢 Warp 的表达能力和可组合性。当我们查看 Warp 代码片段时,它通常读起来像正在发生的事情的故事,这在 Rust 中能够实现是有趣且令人惊讶的。

然而,随着这些不同的函数和过滤器被链接在一起,Warp 中的类型变得非常长且非常复杂,而且难以理解。错误消息也是如此,可能是难以理解的一大堆文本。

Warp 是一个很棒的框架。但是,它「并不是最适合初学者的框架,也不是最流行的框架」。这意味着我们可能在寻找帮助和资源方面会更加困难。但它非常「适用于快速小型应用程序」!

Warp 示例

来自其示例仓库的 WebSocket 聊天的 Warp 应用程序的简化示例:

// 定义了一个静态的原子 usize 计数器,用于为每个连接的用户分配唯一的用户ID。
static NEXT_USER_ID: AtomicUsize = AtomicUsize::new(1);

// 当前连接用户的状态。
//  定义了一个类型别名 Users,它是一个原子引用计数的可读写锁的 HashMap,将用户ID映射到消息的发送器。
// Arc 是原子引用计数的智能指针,RwLock 是读写锁。
// - 键是其id
// - 值是`warp::ws::Message`的发送器
type Users = Arc<RwLock<HashMap<usize, mpsc::UnboundedSender<Message>>>>;

#[tokio::main]
async fn main() {
    // 创建了一个 users 变量,用于存储连接的用户信息
    let users = Users::default();
    // 将其包装成 Warp 过滤器,以便在不同的路由中共享用户状态。
    let users = warp::any().map(move || users.clone());

    // chat 路由处理 WebSocket 握手
    let chat = warp::path("chat")
        // `ws()`过滤器将准备WebSocket握手...
        .and(warp::ws())
        .and(users)
        // 调用 user_connected 函数处理 WebSocket 连接。
        .map(|ws: warp::ws::Ws, users| {
            // 如果握手成功,将调用我们的函数。
            ws.on_upgrade(move |socket| user_connected(socket, users))
        });

    // 处理 HTTP GET 请求,返回一个包含聊天室链接的 html 页面
    let index = warp::path::end().map(|| warp::reply::html(INDEX_HTML));

    let routes = index.or(chat);

    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;
}


async fn user_connected(ws: WebSocket, users: Users) {
    // 使用计数器为此用户分配新的唯一ID。
    let my_id = NEXT_USER_ID.fetch_add(1, Ordering::Relaxed);

    eprintln!("new chat user: {}", my_id);

    // 将套接字拆分为消息的发送器和接收器。
    let (mut user_ws_tx, mut user_ws_rx) = ws.split();
    // 创建一个新的消息通道 (mpsc::unbounded_channel) 用于将用户的消息广播给其他用户
    let (tx, rx) = mpsc::unbounded_channel();
    let mut rx = UnboundedReceiverStream::new(rx);

    tokio::task::spawn(async move {
        // 不断接收用户的消息。一旦用户断开连接,就会退出这个循环。
        while let Some(message) = rx.next().await {
            user_ws_tx
                .send(message)
                .unwrap_or_else(|e| {
                    eprintln!("websocket send error: {}", e);
                })
                .await;
        }
    });

    //将发送器保存在我们的已连接用户列表中。
    users.write().await.insert(my_id, tx);

    // 返回一个基本上是管理此特定用户连接的状态机的“Future”。

    // 每当用户发送消息时,将其广播给
    // 所有其他用户...
    while let Some(result) = user_ws_rx.next().await {
        let msg = match result {
            Ok(msg) => msg,
            Err(e) => {
                eprintln!("websocket error(uid={}): {}", my_id, e);
                break;
            }
        };
        user_message(my_id, msg, &users).await;
    }

    // 只要用户保持连接,user_ws_rx流就会继续处理。一旦他们断开连接,那么...
    user_disconnected(my_id, &users).await;
}

// 处理用户发送的消息。它跳过非文本消息,将文本消息格式化为 <User#ID>: Message,然后将其广播给所有其他用户。
async fn user_message(my_id: usize, msg: Message, users: &Users) {
    // 跳过任何非文本消息...
    let msg = if let Ok(s) = msg.to_str() {
        s
    } else {
        return;
    };

    let new_msg = format!("<User#{}>: {}", my_id, msg);

    // 来自此用户的新消息,将其发送给所有其他用户(除了相同的uid)...
    for (&uid, tx) in users.read().await.iter() {
        if my_id != uid {
            if let Err(_disconnected) = tx.send(Message::text(new_msg.clone())) {
                // 发送器已断开连接,我们的`user_disconnected`代码
                // 应该在另一个任务中执行,这里没有更多的事情要做。
            }
        }
    }
}

async fn user_disconnected(my_id: usize, users: &Users) {
    eprintln!("good bye user: {}", my_id);

    // 流关闭,因此从用户列表中删除
    users.write().await.remove(&my_id);
}

Warp 特点

  • 函数式方法。
  • 良好的表达能力。
  • 通过接近 Tokio、Tower 和 Hyper 构建强大的生态系统。
  • 不适合初学者的框架

5. Tide

Tide[8] 是一个建立在 async-std 运行时之上的「极简主义 Web 框架」。极简主义的方法意味着我们得到了一个非常小的 API 表面。Tide 中的处理函数是 async fn,接受一个 Request 并返回一个 Response 的 tide::Result。提取数据或发送正确的响应格式由我们自行完成。

虽然这可能对我们来说是更多的工作,但也更直接,意味着我们完全掌控正在发生的事情。在某些情况下,能够离 HTTP 请求和响应如此近是一种愉悦,使事情变得更容易。

Tide 的中间件方法与我们从 Tower 中了解的类似,但 Tide 公开了 async trait crate,使实现变得更加容易。

Tide 示例

来自其示例仓库的用户会话示例:

// async-std crate 提供的异步 main 函数。它返回一个 Result,表示可能的错误。
#[async_std::main]
async fn main() -> Result<(), std::io::Error> {
    // 使用 femme crate 启用颜色日志。这是一个美观的日志记录库,可以使日志输出更易读。
    femme::start();
    // 创建一个 Tide 应用程序实例
    let mut app = tide::new();
    // 添加一个日志中间件,用于记录请求和响应的日志信息。
    app.with(tide::log::LogMiddleware::new());
    // 添加一个会话中间件,用于处理会话数据。这里使用内存存储,并提供一个密钥(TIDE_SECRET),用于加密和验证会话数据。
    app.with(tide::sessions::SessionMiddleware::new(
        tide::sessions::MemoryStore::new(),
        std::env::var("TIDE_SECRET")
            .expect(
                "Please provide a TIDE_SECRET value of at 
                      least 32 bytes in order to run this example",
            )
            .as_bytes(),
    ));
    // 添加一个 Before 中间件,它在处理请求之前执行。在这里,它用于增加访问计数,存储在会话中。
    app.with(tide::utils::Before(
        |mut request: tide::Request<()>| async move {
            let session = request.session_mut();
            let visits: usize = session.get("visits").unwrap_or_default();
            session.insert("visits", visits + 1).unwrap();
            request
        },
    ));
    // 定义了一个处理根路径的GET请求的路由。这个路由通过 async move 来处理请求,获取会话中的访问计数,并返回一个包含访问次数的字符串。
    app.at("/").get(|req: tide::Request<()>| async move {
        let visits: usize = req.session().get("visits").unwrap();
        Ok(format!("you have visited this website {} times", visits))
    });
    // 定义了一个处理 "/reset" 路径的GET请求的路由。这个路由通过 async move 处理请求,将会话数据清除,然后重定向到根路径
    app.at("/reset")
        .get(|mut req: tide::Request<()>| async move {
            req.session_mut().destroy();
            Ok(tide::Redirect::new("/"))
        });
    // 启动应用程序并监听在 "127.0.0.1:8080" 地址上。使用 await? 处理可能的启动错误。
    app.listen("127.0.0.1:8080").await?;

    Ok(())
}

Tide 简要概述

  • 极简主义方法。
  • 使用 async-std 运行时。
  • 简单的处理函数。
  • 异步特性的试验场。

6. Poem

Poem[9] 声称自己是一个功能齐全但易于使用的 Web 框架。乍一看,它的使用方式与 Axum 非常相似,唯一的区别是它需要使用相应的宏标记处理程序函数。它还建立在 Tokio 和 Hyper 之上,完全兼容 Tower 中间件,同时仍然暴露自己的中间件特性。

Poem 的中间件特性也非常简单易用。我们可以直接为所有或特定的 Endpoint(Poem 表达一切都可以处理 HTTP 请求的方式)实现该特性,或者只需编写一个接受 Endpoint 作为参数的异步函数。

Poem 不仅与更广泛的生态系统中的许多功能兼容,而且还具有丰富的功能,包括对 OpenAPI 和 Swagger 文档的全面支持。它不仅限于基于 HTTP 的 Web 服务,还可以用于基于 Tonic 的 gRPC 服务,甚至在 Lambda 函数中使用,而无需切换框架。添加对 OpenTelemetry、redis、Prometheus 等的支持,我们就可以勾选所有现代企业级应用程序 Web 框架的所有框。

Poem 仍然处于 0.x 版本,但如果保持势头并交付出色的 1.0 版本,这将是一个值得关注的框架!

Poem 示例

来自其示例仓库的 WebSocket 聊天的缩写版本:

// 注解表示这是一个处理器函数,用于处理 WebSocket 请求
#[handler]
fn ws(
    // 提取了 WebSocket 路径中的名字参数
    Path(name): Path<String>,
    // WebSocket 对象,表示与客户端的连接
    ws: WebSocket,
    // 是一个数据提取器,用于获取广播通道的发送器。
    sender: Data<&tokio::sync::broadcast::Sender<String>>,
) -> impl IntoResponse {
    // 克隆了广播通道的发送器 sender。
    let sender = sender.clone();
    // 它订阅了广播通道,创建了一个接收器 receiver
    let mut receiver = sender.subscribe();
    //  处理 WebSocket 连接升级
    ws.on_upgrade(move |socket| async move {
        // 将连接的读写部分拆分为 sink 和 stream
        let (mut sink, mut stream) = socket.split();
        
        // 从 WebSocket 客户端接收消息
        // 如果是文本消息,则将其格式化为 {name}: {text} 的形式,并通过广播通道发送。
        // 如果发送失败(例如,通道关闭),则任务终止。

        tokio::spawn(async move {
            while let Some(Ok(msg)) = stream.next().await {
                if let Message::Text(text) = msg {
                    if sender.send(format!("{name}: {text}")).is_err() {
                        break;
                    }
                }
            }
        });
        // 从广播通道接收消息,并将其发送到 WebSocket 客户端
        tokio::spawn(async move {
            while let Ok(msg) = receiver.recv().await {
                if sink.send(Message::Text(msg)).await.is_err() {
                    break;
                }
            }
        });
    })
}

#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
    // 使用 tide::Route 创建了一个路由,其中包括两个路径:
    // - / 路径处理 HTTP GET 请求,调用 index 函数。
    // - /ws/:name 路径处理 WebSocket 请求,调用 ws 函数。
    let app = Route::new().at("/", get(index)).at(
        "/ws/:name",
        // 通过 tokio::sync::broadcast::channel 创建一个广播通道;
        // 并通过 tokio::sync::broadcast::channel::<String>(32).0 
        //   获取其发送器,将其作为数据传递给 ws 处理函数
        get(ws.data(tokio::sync::broadcast::channel::<String>(32).0)),
    );
    // 创建了一个服务器实例
    Server::new(TcpListener::bind("127.0.0.1:3000"))
         // 启动服务器,并等待其完成运行。
        .run(app)
        .await
}

Poem 简要概述

  • 丰富的功能集。
  • 与 Tokio 生态系统兼容。
  • 易于使用。
  • 适用于 gRPC 和 Lambda。

后记

正如我们所见,Rust Web 框架的世界非常多样化。没有一种解决方案适用于所有情况,我们需要选择最符合我们需求的框架。如果我们刚刚开始,我建议我们选择 Actix 或 Axum,因为它们是最适合初学者的框架,而且它们有着出色的文档。



Tags:Web 框架   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Python框架怎么选?5 款主流 Web 框架对比
Web 开发框架多如牛毛,本文好学编程仅选择了几个主要流行的框架进行了介绍,后续我会再分享其他好用、高效的 Web 框架。欢迎关注。在进行 Web 开发时,选择合适的框架是一个关键...【详细内容】
2023-12-27  Search: Web 框架  点击:(102)  评论:(0)  加入收藏
你应该知晓的 Rust Web 框架
前言在之前的用 Rust 搭建 React Server Components 的 Web 服务器我们利用了Axum构建了RSC的服务器。也算是用Rust在构建Web服务上的小试牛刀。虽然说Axum在Rust Web应用中...【详细内容】
2023-12-07  Search: Web 框架  点击:(164)  评论:(0)  加入收藏
fastapi python 中的异步 io 高性能 web 框架
fastapiFastAPI 是一个基于 Python 的现代、快速(高性能)的 Web 框架,用于构建 API。它具有简单易用的语法和高度集成的特性,旨在提供高效的开发体验和出色的性能。‬项目特性 ...【详细内容】
2023-08-13  Search: Web 框架  点击:(259)  评论:(0)  加入收藏
Python Django Web 框架编程 - Django 管理工具
安装 Django 之后,默认即安装了django-admin。在命令提示符中输入下面的命令,就会列出django-admin 的常用命令:django-admin 在Django里django-admin.py和manage.py都是Djang...【详细内容】
2023-04-11  Search: Web 框架  点击:(273)  评论:(0)  加入收藏
最新的 web 框架性能报告出炉
大家好,我是Echa。好消息,Astro 官网Blog 中 Fred Schott 大佬发文公布了 Web 框架性能报告清单,如何让前端开发者们更好的选择前端框架,以及相关性能和在Web 上整体运作流程...【详细内容】
2023-03-14  Search: Web 框架  点击:(174)  评论:(0)  加入收藏
2023 年 Web 框架性能报告
这份报告的目的是查看真实世界的数据,以更好地理解框架选择、性能和 web 上的实际用户体验之间的关系。本文将尝试阐明几个关键问题: 现代 Web 框架在现实世界的使用和性能方...【详细内容】
2023-03-13  Search: Web 框架  点击:(153)  评论:(0)  加入收藏
动手搭建 Web 框架深入了解 Web 框架的本质
Web 框架的本质及自定义 Web 框架我们可以这样理解:所有的 Web 应用本质上就是一个 socket 服务端,而用户的浏览器就是一个 socket 客户端,基于请求做出响应。客户都先请求,服务...【详细内容】
2022-10-06  Search: Web 框架  点击:(316)  评论:(0)  加入收藏
Python Web 框架:你需要知道的一切
每日分享最新,最流行的软件开发知识与最新行业趋势,希望大家能够一键三连,多多支持,跪求关注,点赞,留言。在这篇文章中了解一些可供您使用的最佳 Python Web 框架,您可以考虑将它们...【详细内容】
2022-09-29  Search: Web 框架  点击:(381)  评论:(0)  加入收藏
GitLab 技术选型为何不同:坚持用 Web 框架十多年、坚决不用微服务
关于过气网红编程语言 Ruby,我们此前曾发过一篇文章去回顾其大受追捧的过往,并讨论了它每况愈下的生存状态。不过人气并不能直接说明语言质量差,一方面 Ruby on Rails(用 Ruby...【详细内容】
2022-07-08  Search: Web 框架  点击:(263)  评论:(0)  加入收藏
FastAPI - 一款新型的 Python Web 框架(对比 Flask)
近日只是为了想尽办法为 Flask 实现 Swagger UI 文档功能,基本上要让 Flask 配合 Flasgger, 所以写了篇 Flask 应用集成 Swagger UI 。然而不断的 Google 过程中偶然间发现了...【详细内容】
2021-12-23  Search: Web 框架  点击:(1118)  评论:(0)  加入收藏
▌简易百科推荐
对于微服务架构监控应该遵守的原则
随着软件交付方式的变革,微服务架构的兴起使得软件开发变得更加快速和灵活。在这种情况下,监控系统成为了微服务控制系统的核心组成部分。随着软件的复杂性不断增加,了解系统的...【详细内容】
2024-04-03  步步运维步步坑    Tags:架构   点击:(4)  评论:(0)  加入收藏
大模型应用的 10 种架构模式
作者 | 曹洪伟在塑造新领域的过程中,我们往往依赖于一些经过实践验证的策略、方法和模式。这种观念对于软件工程领域的专业人士来说,已经司空见惯,设计模式已成为程序员们的重...【详细内容】
2024-03-27    InfoQ  Tags:架构模式   点击:(13)  评论:(0)  加入收藏
哈啰云原生架构落地实践
一、弹性伸缩技术实践1.全网容器化后一线研发的使用问题全网容器化后一线研发会面临一系列使用问题,包括时机、容量、效率和成本问题,弹性伸缩是云原生容器化后的必然技术选择...【详细内容】
2024-03-27  哈啰技术  微信公众号  Tags:架构   点击:(10)  评论:(0)  加入收藏
DDD 与 CQRS 才是黄金组合
在日常工作中,你是否也遇到过下面几种情况: 使用一个已有接口进行业务开发,上线后出现严重的性能问题,被老板当众质疑:“你为什么不使用缓存接口,这个接口全部走数据库,这怎么能扛...【详细内容】
2024-03-27  dbaplus社群    Tags:DDD   点击:(11)  评论:(0)  加入收藏
高并发架构设计(三大利器:缓存、限流和降级)
软件系统有三个追求:高性能、高并发、高可用,俗称三高。本篇讨论高并发,从高并发是什么到高并发应对的策略、缓存、限流、降级等。引言1.高并发背景互联网行业迅速发展,用户量剧...【详细内容】
2024-03-13    阿里云开发者  Tags:高并发   点击:(5)  评论:(0)  加入收藏
如何判断架构设计的优劣?
架构设计的基本准则是非常重要的,它们指导着我们如何构建可靠、可维护、可测试的系统。下面是这些准则的转换表达方式:简单即美(KISS):KISS原则的核心思想是保持简单。在设计系统...【详细内容】
2024-02-20  二进制跳动  微信公众号  Tags:架构设计   点击:(36)  评论:(0)  加入收藏
详解基于SpringBoot的WebSocket应用开发
在现代Web应用中,实时交互和数据推送的需求日益增长。WebSocket协议作为一种全双工通信协议,允许服务端与客户端之间建立持久性的连接,实现实时、双向的数据传输,极大地提升了用...【详细内容】
2024-01-30  ijunfu  今日头条  Tags:SpringBoot   点击:(8)  评论:(0)  加入收藏
PHP+Go 开发仿简书,实战高并发高可用微服务架构
来百度APP畅享高清图片//下栽のke:chaoxingit.com/2105/PHP和Go语言结合,可以开发出高效且稳定的仿简书应用。在实现高并发和高可用微服务架构时,我们可以采用一些关键技术。首...【详细内容】
2024-01-14  547蓝色星球    Tags:架构   点击:(114)  评论:(0)  加入收藏
GraalVM与Spring Boot 3.0:加速应用性能的完美融合
在2023年,SpringBoot3.0的发布标志着Spring框架对GraalVM的全面支持,这一支持是对Spring技术栈的重要补充。GraalVM是一个高性能的多语言虚拟机,它提供了Ahead-of-Time(AOT)编...【详细内容】
2024-01-11    王建立  Tags:Spring Boot   点击:(124)  评论:(0)  加入收藏
Spring Boot虚拟线程的性能还不如Webflux?
早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。测试场景作者采用了一个尽可...【详细内容】
2024-01-10  互联网架构小马哥    Tags:Spring Boot   点击:(115)  评论:(0)  加入收藏
站内最新
站内热门
站内头条