48次发布
0.3.0-beta.2 | 2024年2月14日 |
---|---|
0.2.0-beta.18 | 2023年10月6日 |
0.2.0-beta.13 | 2023年7月19日 |
0.2.0-beta.10 | 2023年3月28日 |
0.2.0-alpha.0 | 2021年3月29日 |
#297 in HTTP服务器
用于 apocalypse
160KB
2.5K SLoC
Cataclysm ⛈. 一个简单的Rust HTTP服务器
工作正在进行中:当前状态下的工作部分可用,但将在完整HTTP/1.1服务器功能实现之前持续更新。当达到这种状态时,此说明将删除。
Cataclysm是一个受actix-web启发的http框架,并在tokio之上构建。以下是一个最小的工作示例
use cataclysm::{Server, Branch, http::{Response, Method}};
async fn hello() -> Response {
Response::ok().body("hello")
}
#[tokio::main]
async fn main() {
let server = Server::builder(
Branch::<()>::new("/hello").with(Method::Get.to(hello))
).build().unwrap();
server.run("localhost:8000").await.unwrap();
}
闭包作为回调
在 async closures
变得稳定之前,将闭包作为路径处理程序传递的选项是一个返回异步块的闭包
use cataclysm::{Server, Branch, http::{Response, Method}};
#[tokio::main]
async fn main() {
let server = Server::builder(
Branch::<()>::new("/data").with(Method::Post.to(|| async {
Response::ok().body("worked!")
}))
).build().unwrap();
server.run("localhost:8000").await.unwrap();
}
提取器
可以通过向回调添加具有实现 Extractor
特质的类型的参数来从HTTP请求中检索一些数据。默认实现列表如下
String
:尝试将正文提取为有效的utf-8字符串。如果操作失败,则返回Bad-RequestVec<u8>
:将http
调用的内容作为字节流返回Request
:返回请求,以便在回调中拥有更多控制Path<T>
:返回路径参数。T必须是元组。Shared<T>
:返回提供给服务器(如果有的话)的共享数据。
将数据共享到服务器函数中
可以通过 ServerBuilder
结构的 share
方法以及 Shared
结构的帮助,在服务器调用之间共享数据。
use cataclysm::{Server, Branch, Shared, http::{Response, Method, Path}};
// Receives a string, and concatenates the shared suffix
async fn index(path: Path<(String,)>, shared: Shared<String>) -> Response {
let (prefix,) = path.into_inner();
let suffix = shared.into_inner();
Response::ok().body(format!("{}{}", prefix, suffix))
}
#[tokio::main]
async fn main() {
// We create our tree structure
let branch = Branch::new("/{:value}").with(Method::Get.to(index));
// We create a server with the given tree structure
let server = Server::builder(branch).share("!!!".into()).build().unwrap();
// And we launch it on the following address
server.run("127.0.0.1:8000").await.unwrap();
}
如果您想共享可变数据,请使用Rust的Mutex
结构(因为Shared
结构已经提供了Arc
包装器)。
SPA和静态文件服务
分支结构同时具有file
方法和defaults_to_file
,用于创建一个简单的SPA服务器,一个允许在提供的文件夹路径中查找包含扩展名的所有路径,另一个则用于在任何没有扩展名的其他匹配路径中提供服务。
use cataclysm::{Server, Branch, http::{Response, Method}};
async fn salute() -> Response {
Response::ok().body("api salute endpoint?")
}
#[tokio::main]
async fn main() {
let branch: Branch<()> = Branch::new("/").files("./static").defaults_to_file("./static/index.html")
.nest(Branch::new("/api/v1/salute").with(Method::Get.to(salute)));
let server = Server::builder(branch).build().unwrap();
server.run("127.0.0.1:8000").await.unwrap();
}
层
Cataclysm允许处理层,也就是中间件。
use cataclysm::{Server, Branch, Additional, Pipeline, http::{Response, Request, Method}};
use std::sync::Arc;
use futures::future::FutureExt;
#[tokio::main]
async fn main() {
let branch = Branch::new("/").with(Method::Get.to(|| async {Response::ok()}))
.layer(|req: Request, pipeline: Box<Pipeline<()>>, ad: Arc<Additional<()>>| async {
// Example of timing layer
println!("Time measuring begins");
let now = std::time::Instant::now();
let request = pipeline.execute(req, ad).await;
let elapsed = now.elapsed().as_nanos();
println!("Process time: {} ns", elapsed);
request
}.boxed());
let server = Server::builder(branch).build().unwrap();
server.run("localhost:8000").await.unwrap();
}
如示例所示,层函数接收一个Request
和一个boxed的Pipeline
枚举。该Pipeline
枚举包含嵌套的futures结构(层加核心处理器),并提供execute
方法以简化事情。此函数必须返回一个Pin<Box<_>>
未来,因此您可以使用futures
crate中的FutureExt
trait的boxed
方法,或者手动包装。
完整日志功能
如果激活了full_log
功能,将通过Debug
和Trace
级别提供日志函数。这可能对调试很有用,但因为它可能会对性能产生重大影响,所以它被设置为可选。
TODO
- 分支创建时,使用/会引起正则表达式问题(通过"{", "}"检测的队列实现修复)
lib.rs
:
Cataclysm:一个简单的HTTP框架
Cataclysm是一个小型个人项目,是一个受actix-web
启发的HTTP框架,并在tokio
之上构建。以下是一个最小的工作示例
extern crate cataclysm;
use cataclysm::{Server, Branch, http::{Response, Method}};
async fn index() -> Response {
Response::ok().body("Hello, World!")
}
#[tokio::main]
async fn main() {
let server = Server::builder(
Branch::<()>::new("/").with(Method::Get.to(index))
).build().unwrap();
server.run("localhost:8000").await.unwrap();
}
依赖项
~18–30MB
~553K SLoC