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没多久,轻喷~

相关推荐
isyuah2 小时前
Miko 框架系列(十四):集成测试
后端·rust
代码笔耕2 小时前
我们这样设计消息中心,解决了业务反复折腾的顽疾
java·后端·架构
chenyuhao20242 小时前
Linux系统编程:多线程同步与单例模式
linux·服务器·c++·后端·单例模式
唐装鼠2 小时前
Rust Turbofish 语法详解(deepseek)
开发语言·后端·rust
Source.Liu2 小时前
【Rust】字符串类型全览:从 UTF-8 到系统路径
rust
码luffyliu2 小时前
Go 语言并发编程:为何它能甩开 Java 等传统后端语言?
java·后端·golang·go
青梅主码2 小时前
微软最新发布《微软2025年新未来工作报告》:AI 如何帮助团队和组织实现集体生产力的提升?
后端
武子康3 小时前
大数据-193 Apache Tez 实战:Hive on Tez 安装配置、DAG原理与常见坑
大数据·后端·apache
青石路3 小时前
用了MySQL的INSERT ON DUPLICATE KEY UPDATE,怎么还报唯一索引冲突错误
后端·sql·mysql