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

相关推荐
梦梦代码精1 小时前
《全栈开源智能体:终结企业AI拼图时代》
人工智能·后端·深度学习·小程序·前端框架·开源·语音识别
Victor3562 小时前
Hibernate(42)在Hibernate中如何实现分页?
后端
Victor3562 小时前
Hibernate(41)Hibernate的延迟加载和急加载的区别是什么?
后端
猪猪拆迁队2 小时前
2025年终总结-都在喊前端已死,这一年我的焦虑、挣扎与重组:AI 时代如何摆正自己的位置
前端·后端·ai编程
ConardLi2 小时前
SFT、RAG 调优效率翻倍!垂直领域大模型评估实战指南
前端·javascript·后端
Hooray3 小时前
2026年,站在职业生涯十字路口的我该何去何从?
前端·后端
唐叔在学习3 小时前
还在申请云服务器来传输数据嘛?试试P2P直连吧
后端·python
开心猴爷4 小时前
iOS 代码混淆在项目中的方式, IPA 级保护实践记录
后端
魅影骑士00104 小时前
柯里化函数
后端·设计模式
JOEH604 小时前
🛡️ 微服务雪崩救星:Sentinel 限流熔断实战,3行代码搞定高可用!
后端·全栈