Miko v0.7 发布:我写的一个 Rust Web 框架,虽然还是个玩具

Miko v0.7 发布:我写的一个 Rust Web 框架,虽然还是个玩具

断断续续写这个框架有一段时间了。起初只是因为在 Rust 里写 Web 服务时,总觉得要在"性能"和"开发体验"之间做妥协。Actix 和 Axum 性能很强,但每次写 Handler 都要手动注册路由,或者搞复杂的 State 传递,我就忍不住怀念 Spring Boot 或者 NestJS 那种"自动装配"的感觉。

于是就有了exum(虽然现在断更了,因为exum是依赖于axum的补丁类似的,写起来总有东西不好实现,所以想着自己搞一个玩玩得了,正好当时没什么事,还正好在学Rust)

于是就有了 Miko。

这只是我的个人作品,现阶段肯定不推荐大家用在严肃的生产环境里(除非你胆子很大并且愿意自己修 Bug)。但如果你想在 Rust 里体验一下"约定优于配置"和"宏魔法",或者想写个 Side Project 玩玩,Miko 可能会让你觉得挺有意思。

最近发了 v0.7 版本,正好跟大家聊聊都更新了啥,顺便介绍下怎么玩。

快速上手:真的很快

既然主打开发体验,那 Hello World 必须足够简单。你不需要手动创建 Router,也不用显式启动 Server,只需要定义 handler 和一个宏: (甚至返回类型都不用指定,发现你没指定会自己加个impl IntoResponse)

rust 复制代码
use miko::*;
use miko::macros::*;

#[get("/")]
async fn hello() {
    "Hello, Miko!"
}

#[miko]
async fn main() {
    // 啥都不用写,框架自动扫描路由并启动
}

运行 cargo run,打开 localhost:8080,搞定。

实时通讯:从未如此简单

由于一些神奇的操作,貌似对实时通讯(SSE 和 WebSocket)做了大幅简化。

SSE (Server-Sent Events)

现在,你只需要返回一个闭包,框架就会自动把它放到后台任务里跑,甚至连 Response 都不用自己构造:

rust 复制代码
#[get("/events")]
async fn events() -> impl IntoResponse {
    // 直接返回一个闭包,接受 sender 参数
    |sender: SseSender| async move {
        for i in 0..5 {
            // 发送数据,or_break() 会在客户端断开时自动停止任务(记得加上sse参数才能捕获这个断开,就#[miko(sse)])
            sender.send(format!("Count: {}", i)).await.or_break();
            tokio::time::sleep(std::time::Duration::from_secs(1)).await;
        }
    }
}

WebSocket

WebSocket 也一样,不用自己处理 Upgrade Header,直接用 spawn_ws_event

rust 复制代码
#[get("/ws")]
async fn ws(mut req: Req) -> AppResult<Resp> {
    // 自动处理握手,并在回调中处理连接
    spawn_ws_event(|mut io| async move {
        while let Some(Ok(msg)) = io.next().await {
            if msg.is_text() {
                io.send("Received!").await.unwrap();
            }
        }
    }, &mut req, None).map_err(AppError::from)
}

终于不用手写 Tower Layer 了

在 Rust Web 开发里,中间件(Middleware)一直是个门槛。虽然 tower 的 Layer 抽象很美妙,但要自己实现 Service trait 真的很繁琐。

我之前也是深受其苦,所以这次加了个大杀器:#[middleware] 宏。

现在写个鉴权中间件或者日志中间件,跟写普通函数没啥区别:

rust 复制代码
#[middleware]
async fn my_logger(#[config("app.name")] app_name: String) -> AppResult<Resp> {
    println!("Request to {}", app_name);
    // 继续执行下一个 handler
    _next.run(_req).await
}

它会自动编译成一个标准的 tower::Layer。你能直接在参数里注入依赖、读取配置,甚至能直接处理错误。

测试,要快,还要简单

以前做集成测试,总得绑定个本地端口,经常遇到端口冲突,或者因为网络协议栈导致测试跑得慢。

所以我搞了个 TestClient。它能在同一个进程里模拟 HTTP 请求,直接把请求分发到路由处理逻辑,不走网络层

配合 #[miko(build)] 宏,现在的测试代码可以写得很干净:

rust 复制代码
#[tokio::test]
async fn test_api() {
    // 直接复用 main.rs 里的构建逻辑
    let app = app::create_app().await; 
    let client = app.test_client();

    client.get("/api/users")
        .send().await
        .assert_status(200);
}

其他一些实用的改进

  1. Panic 也能兜底了:Handler 崩了会返回 500 错误,服务还能接着跑。
  2. 依赖注入变聪明了 :支持更复杂的依赖关系,还加了个 prewarm 参数,可以让数据库连接池在启动时就预热好。
  3. 生态整合utoipa (OpenAPI) 和 garde (验证库) 直接 re-export,开箱即用。
  4. 优雅停机:也是经过好久之后终于端上来了,暂时是最大等待30s

试试看?

代码都在 GitHub 上:github.com/isyuah/miko

目前版本是 v0.7.0。如果你对它感兴趣,欢迎 cargo add miko --features full 玩一玩。

如果你在使用过程中遇到了 Panic,或者觉得哪里设计得很蠢,欢迎提 Issue 喷我(或者帮我修一下),毕竟这就是开源的乐趣嘛。

叠个甲(,我才刚学Rust没多久,轻喷~

相关推荐
毕设源码-邱学长15 分钟前
【开题答辩全过程】以 基于SpringBoot的理工学院学术档案管理系统为例,包含答辩的问题和答案
java·spring boot·后端
修己xj24 分钟前
SpringBoot解析.mdb文件实战指南
java·spring boot·后端
lpfasd12342 分钟前
Spring Boot 定时任务详解(从入门到实战)
spring boot·后端·python
moxiaoran57531 小时前
Go语言的文件操作
开发语言·后端·golang
赴前尘1 小时前
记一次golang进程执行卡住的问题排查
开发语言·后端·golang
码农小卡拉1 小时前
Prometheus 监控 SpringBoot 应用完整教程
spring boot·后端·grafana·prometheus
计算机毕设VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue球鞋购物系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
苏渡苇2 小时前
用 Spring Boot 项目给工厂装“遥控器”:一行 API 控制现场设备!
java·人工智能·spring boot·后端·网络协议·边缘计算
初恋叫萱萱2 小时前
基于 Rust 与 DeepSeek 构建高性能 Text-to-SQL 数据库代理服务
数据库·sql·rust
短剑重铸之日2 小时前
《设计模式》第五篇:策略模式
java·后端·设计模式·策略模式