10 个版本
0.3.1 | 2023 年 6 月 3 日 |
---|---|
0.3.0 | 2021 年 4 月 13 日 |
0.2.4 | 2021 年 4 月 5 日 |
0.2.3 | 2021 年 2 月 5 日 |
0.1.0 | 2020 年 8 月 17 日 |
#370 在 HTTP 服务器
37 每月下载次数
80KB
2.5K SLoC
Eve-rs
Eve-rs 是一个基于中间件的 Rust HTTP 框架,灵感来源于 ExpressJS 框架。
示例
让我们使用 eve-rs 创建一个示例应用程序,以直观的方式更好地理解框架。
创建 cargo 项目,这里我们将其命名为 demo,然后在 Cargo.toml
文件中,在依赖关系部分添加以下依赖项。
[dependencies]
eve-rs = '0.2.0'
log = '0.4.8'
tokio = {version = '0.2.22', features = ['full']}
更新 toml 文件后,我们然后在 main.rs
文件中输入以下代码
导入 eve-rs 包
第一步是将 eve_rs
带入项目的范围。因此,我们添加以下行
use eve_rs::{App as DemoApp, Context, DefaultContext, NextHandler, Error, listen, Request, DefaultMiddleware};
中间件
就像在 express
框架中一样,中间件基本上是一个可以访问请求和响应对象的函数。在 eve-rs
中,我们使用相同的术语,并使用中间件进行路由。
对于我们的示例应用程序,我们将创建一个名为 plaintext
的单个中间件,该中间件将在 GET 请求上打印纯文本。
中间件接受两个参数,Context
和 NextHandler
。
Context
提供了与请求相关的更多信息的 API。例如,获取请求正文、请求状态、内容类型等。由于它是一个 trait(类似于其他编程语言中的接口),我们可以在应用程序中定义自己的上下文,另一方面,用户可以使用 eve 提供的 DefaultContext
。
NextHandler
是序列中的下一个中间件。也就是说,如果当前中间件在完成处理且没有抛出错误后传递,则下一个中间件将被调用。
在我们的示例代码中,我们没有要执行的下一个中间件,因此我们将 _next
作为参数。
async fn plaintext(
mut context: DefaultContext,
_next: NextHandler<DefaultContext>
) -> Result<DefaultContext, Error<DefaultContext>> {
let val = "Hello, World!";
context.body(val);
/**
Use this if your code uses a next handler.
let response = next(context).await;
return response;
*/
Ok(context)
}
创建应用程序
我们的下一步是创建一个eve应用。在eve-rs中的App结构体提供了一个create()
函数,用于创建App。该函数接收两个参数:context_generator
和state
。
context_generator
是一个用于为我们的中间件创建上下文的函数。它接收两个参数:Request
和state
。在这里,状态可以是我们的应用需要拥有的任何配置。假设我们需要应用拥有一些状态,那么我们将以以下方式传递状态
pub struct State {
pub database_name : String;
}
fn context_generator(request : Request, state : &State) -> YourAppContext {
let state = state.clone();
YourAppContext::new(request, state)
}
由于在我们的例子中使用了DefaultContext
,我们可以不传递状态就创建一个上下文。
fn default_context_generator(request: Request, _ : &()) -> DefaultContext {
// default context has no state as an argument.
DefaultContext::new(request)
}
一旦我们有了上下文生成器,我们就可以继续创建应用。
pub fn create_app() -> DemoApp<DefaultContext, DefaultMiddleware<()>, ()> {
DemoApp::<DefaultContext, DefaultMiddleware<()>, ()>::create(default_context_generator, ())
}
在上面的代码中,第二个参数是存储在DemoApp
中的状态,由于我们没有状态,我们向create函数传递了()
。
应用创建后,我们可以通过使用app.use_middleware()
函数在应用的范围内添加中间件。
app.use_middleware("/plaintext", &[DefaultMiddleware::new(|context, next| {
Box::pin(async move {
plaintext(context, next).await
})
})])
以下是结合上述所有方法的代码示例。
// Bring eve-rs modules to the program scope.
use eve_rs::{App as DemoApp, Context, DefaultContext, NextHandler, Error, listen, Request, DefaultMiddleware};
// middleware
async fn plaintext(
mut context: DefaultContext,
_: NextHandler<DefaultContext>
) -> Result<DefaultContext, Error<DefaultContext>> {
let val = "Hello, World!";
context.body(val);
Ok(context)
}
// function to create an eve-rs app.
pub fn create_app() -> DemoApp<DefaultContext, DefaultMiddleware<()>, ()> {
DemoApp::<DefaultContext, DefaultMiddleware<()>, ()>::create(default_context_generator, ())
}
// context generator.
fn default_context_generator(request: Request, _: &()) -> DefaultContext {
// default context has no state as an argument.
DefaultContext::new(request)
}
#[async_std::main]
async fn main() {
println!("Starting server...");
// call function to create default app.
let mut app = create_app();
// add middleware to the stack.
// Can also be one of:
// get
// post
// put
// delete
// head
// options
// connect
// patch
// trace
app.use_middleware("/plaintext", &[DefaultMiddleware::new(|context, next| {
Box::pin(async move {
plaintext(context, next).await
})
})]);
// assign port number.
let port = 8080;
log::info!("Listening for connections on 127.0.0.1:{}", port);
listen(app, ([127, 0, 0, 1], port), None).await;
}
使用cargo build
命令构建项目。
使用cargo run
命令运行项目。
在上面的例子中,我们使用了DefaultContext
作为Context
。这意味着eve-rs允许我们以自己的方式实现Context
。为了简化,我们使用了DefaultContext
。
同样,对于DefaultMiddleware
也是如此。在这里,我们使用了默认实现。您可以自由实现自己的。
致谢
本项目深受Thruster的启发。这个框架与Thruster非常相似,只是在一些小的设计决策上有所不同。虽然这个框架目前在我们公司的生产环境中使用,但如果您在寻找一个更成熟的项目,您绝对应该选择Thruster。
非常感谢@trezm在开发过程中对我的帮助。
依赖关系
~12–29MB
~453K SLoC