5个不稳定版本
0.3.2 | 2022年6月16日 |
---|---|
0.3.1 | 2022年6月11日 |
0.3.0 | 2022年6月9日 |
0.2.0 | 2022年4月26日 |
0.1.0 | 2022年4月26日 |
#837 in HTTP服务器
每月 22 次下载
145KB
3K SLoC
注意:此库已被重命名为 Servlin。
Beatrice
Rust的一个模块化HTTP服务器库。
功能
forbid(unsafe_code)
- 线程化请求处理器
FnOnce(Request) ->Response+ 'static + Clone + Send + Sync
- 内部使用异步代码,在负载下表现优异
- JSON
- 服务器端事件(SSE)
- 将大型请求体保存到临时文件
- 发送100-Continue
- 限制线程和连接数
- 模块化:自定义日志记录、编写内部方法的自定义版本等。
- 没有宏或复杂的类型参数
- 良好的测试覆盖率(63%)
限制
- 新项目,尚未在生产环境中证明。
- 待办事项
- 请求超时
chunked
转发编码的请求体- gzip
- brotli
- TLS
- 通过ACME自动获取TLS证书
- 当接近连接限制时,丢弃空闲连接。
- 拒绝服务缓解:源节流,最小吞吐量
- 完整的功能测试套件
- 缺少负载测试
- 磁盘空间使用限制
示例
完整示例: examples/
。
简单示例
use beatrice::{
print_log_response,
socket_addr_127_0_0_1,
HttpServerBuilder,
Request,
Response
};
use beatrice::reexport::{safina_executor, safina_timer};
use serde::Deserialize;
use serde_json::json;
use std::sync::Arc;
use temp_dir::TempDir;
struct State {}
fn hello(_state: Arc<State>, req: &Request) -> Result<Response, Response> {
#[derive(Deserialize)]
struct Input {
name: String,
}
let input: Input = req.json()?;
Ok(Response::json(200, json!({"message": format!("Hello, {}!", input.name)}))
.unwrap())
}
fn handle_req(state: Arc<State>, req: &Request) -> Result<Response, Response> {
match (req.method(), req.url().path()) {
("GET", "/ping") => Ok(Response::text(200, "ok")),
("POST", "/hello") => hello(state, req),
_ => Ok(Response::text(404, "Not found")),
}
}
let state = Arc::new(State {});
let request_handler = move |req: Request| {
print_log_response(&req, handle_req(state, &req))
};
let cache_dir = TempDir::new().unwrap();
safina_timer::start_timer_thread();
let executor = safina_executor::Executor::new(1, 9).unwrap();
executor.block_on(
HttpServerBuilder::new()
.listen_addr(socket_addr_127_0_0_1(8000))
.max_conns(1000)
.small_body_len(64 * 1024)
.receive_large_bodies(cache_dir.path())
.spawn_and_join(request_handler)
).unwrap();
Cargo Geiger 安全报告
Metric output format: x/y
x = unsafe code used by the build
y = total unsafe code found in the crate
Symbols:
🔒 = No `unsafe` usage found, declares #![forbid(unsafe_code)]
❓ = No `unsafe` usage found, missing #![forbid(unsafe_code)]
☢️ = `unsafe` usage found
Functions Expressions Impls Traits Methods Dependency
0/0 0/0 0/0 0/0 0/0 🔒 beatrice 0.3.2
0/0 4/4 0/0 0/0 2/2 ☢️ ├── async-fs 1.5.0
0/0 51/51 14/14 0/0 0/0 ☢️ │ ├── async-lock 2.5.0
0/0 106/116 4/8 0/0 0/0 ☢️ │ │ └── event-listener 2.5.2
0/0 28/28 4/4 0/0 0/0 ☢️ │ ├── blocking 1.2.0
0/0 0/0 0/0 0/0 0/0 🔒 │ │ ├── async-channel 1.6.1
0/0 155/155 2/2 0/0 1/1 ☢️ │ │ │ ├── concurrent-queue 1.2.2
0/0 0/0 0/0 0/0 0/0 🔒 │ │ │ │ └── cache-padded 1.2.0
0/0 106/116 4/8 0/0 0/0 ☢️ │ │ │ ├── event-listener 2.5.2
0/0 30/30 2/2 0/0 0/0 ☢️ │ │ │ └── futures-core 0.3.21
1/1 802/802 4/4 0/0 10/10 ☢️ │ │ ├── async-task 4.2.0
0/0 26/26 2/2 0/0 0/0 ☢️ │ │ ├── atomic-waker 1.0.0
0/0 0/0 0/0 0/0 0/0 🔒 │ │ ├── fastrand 1.7.0
0/0 0/0 0/0 0/0 0/0 ❓ │ │ ├── futures-lite 1.12.0
0/0 0/0 0/0 0/0 0/0 🔒 │ │ │ ├── fastrand 1.7.0
0/0 30/30 2/2 0/0 0/0 ☢️ │ │ │ ├── futures-core 0.3.21
0/0 0/0 0/0 0/0 0/0 ❓ │ │ │ ├── futures-io 0.3.21
36/37 2067/2144 0/0 0/0 21/21 ☢️ │ │ │ ├── memchr 2.5.0
1/21 10/368 0/2 0/0 5/40 ☢️ │ │ │ │ └── libc 0.2.126
0/0 0/0 0/0 0/0 0/0 🔒 │ │ │ ├── parking 2.0.0
0/0 11/165 0/0 0/0 2/2 ☢️ │ │ │ ├── pin-project-lite 0.2.9
0/0 21/21 0/0 0/0 4/4 ☢️ │ │ │ └── waker-fn 1.1.0
1/1 75/117 4/6 0/0 2/3 ☢️ │ │ └── once_cell 1.12.0
0/0 0/0 0/0 0/0 0/0 ❓ │ └── futures-lite 1.12.0
0/0 0/0 0/0 0/0 0/0 🔒 ├── async-net 1.6.1
0/0 22/22 0/0 0/0 0/0 ☢️ │ ├── async-io 1.7.0
0/0 155/155 2/2 0/0 1/1 ☢️ │ │ ├── concurrent-queue 1.2.2
0/0 0/0 0/0 0/0 0/0 ❓ │ │ ├── futures-lite 1.12.0
1/21 10/368 0/2 0/0 5/40 ☢️ │ │ ├── libc 0.2.126
1/1 16/18 1/1 0/0 0/0 ☢️ │ │ ├── log 0.4.17
0/0 0/0 0/0 0/0 0/0 ❓ │ │ │ ├── cfg-if 1.0.0
0/0 5/5 0/0 0/0 0/0 ☢️ │ │ │ └── serde 1.0.137
0/0 0/0 0/0 0/0 0/0 ❓ │ │ │ └── serde_derive 1.0.137
0/0 12/12 0/0 0/0 3/3 ☢️ │ │ │ ├── proc-macro2 1.0.39
0/0 4/4 0/0 0/0 0/0 ☢️ │ │ │ │ └── unicode-ident 1.0.0
0/0 0/0 0/0 0/0 0/0 ❓ │ │ │ ├── quote 1.0.18
0/0 12/12 0/0 0/0 3/3 ☢️ │ │ │ │ └── proc-macro2 1.0.39
0/0 50/50 3/3 0/0 2/2 ☢️ │ │ │ └── syn 1.0.96
0/0 12/12 0/0 0/0 3/3 ☢️ │ │ │ ├── proc-macro2 1.0.39
0/0 0/0 0/0 0/0 0/0 ❓ │ │ │ ├── quote 1.0.18
0/0 4/4 0/0 0/0 0/0 ☢️ │ │ │ └── unicode-ident 1.0.0
1/1 75/117 4/6 0/0 2/3 ☢️ │ │ ├── once_cell 1.12.0
0/0 0/0 0/0 0/0 0/0 🔒 │ │ ├── parking 2.0.0
0/0 0/9 1/6 0/0 0/0 ☢️ │ │ ├── polling 2.2.0
0/0 0/0 0/0 0/0 0/0 ❓ │ │ │ ├── cfg-if 1.0.0
1/21 10/368 0/2 0/0 5/40 ☢️ │ │ │ ├── libc 0.2.126
1/1 16/18 1/1 0/0 0/0 ☢️ │ │ │ └── log 0.4.17
0/0 24/24 0/0 0/0 3/3 ☢️ │ │ ├── slab 0.4.6
0/0 5/5 0/0 0/0 0/0 ☢️ │ │ │ └── serde 1.0.137
3/6 528/641 2/4 0/0 3/4 ☢️ │ │ ├── socket2 0.4.4
1/21 10/368 0/2 0/0 5/40 ☢️ │ │ │ └── libc 0.2.126
0/0 21/21 0/0 0/0 4/4 ☢️ │ │ └── waker-fn 1.1.0
0/0 28/28 4/4 0/0 0/0 ☢️ │ ├── blocking 1.2.0
0/0 0/0 0/0 0/0 0/0 ❓ │ └── futures-lite 1.12.0
0/0 0/0 0/0 0/0 0/0 🔒 ├── fixed-buffer 0.5.0
0/0 0/0 0/0 0/0 0/0 ❓ │ └── futures-io 0.3.21
0/0 0/0 0/0 0/0 0/0 ❓ ├── futures-io 0.3.21
0/0 0/0 0/0 0/0 0/0 ❓ ├── futures-lite 1.12.0
0/0 0/0 0/0 0/0 0/0 ❓ ├── include_dir 0.7.2
0/0 0/0 0/0 0/0 0/0 ❓ │ └── include_dir_macros 0.7.2
0/0 12/12 0/0 0/0 3/3 ☢️ │ ├── proc-macro2 1.0.39
0/0 0/0 0/0 0/0 0/0 ❓ │ └── quote 1.0.18
0/0 0/0 0/0 0/0 0/0 🔒 ├── permit 0.1.4
0/0 0/0 0/0 0/0 0/0 🔒 ├── safe-regex 0.2.5
0/0 0/0 0/0 0/0 0/0 🔒 │ └── safe-regex-macro 0.2.5
0/0 0/0 0/0 0/0 0/0 🔒 │ ├── safe-proc-macro2 1.0.36
0/0 0/0 0/0 0/0 0/0 🔒 │ │ └── unicode-xid 0.2.3
0/0 0/0 0/0 0/0 0/0 🔒 │ └── safe-regex-compiler 0.2.5
0/0 0/0 0/0 0/0 0/0 🔒 │ ├── safe-proc-macro2 1.0.36
0/0 0/0 0/0 0/0 0/0 🔒 │ └── safe-quote 1.0.15
0/0 0/0 0/0 0/0 0/0 🔒 │ └── safe-proc-macro2 1.0.36
0/0 0/0 0/0 0/0 0/0 🔒 ├── safina-executor 0.3.3
0/0 0/0 0/0 0/0 0/0 🔒 │ ├── safina-sync 0.2.4
0/0 0/0 0/0 0/0 0/0 🔒 │ └── safina-threadpool 0.2.4
0/0 0/0 0/0 0/0 0/0 🔒 ├── safina-sync 0.2.4
0/0 0/0 0/0 0/0 0/0 🔒 ├── safina-timer 0.1.11
1/1 75/117 4/6 0/0 2/3 ☢️ │ └── once_cell 1.12.0
0/0 5/5 0/0 0/0 0/0 ☢️ ├── serde 1.0.137
0/0 4/7 0/0 0/0 0/0 ☢️ ├── serde_json 1.0.81
0/0 7/7 0/0 0/0 0/0 ☢️ │ ├── itoa 1.0.2
7/9 587/723 0/0 0/0 2/2 ☢️ │ ├── ryu 1.0.10
0/0 5/5 0/0 0/0 0/0 ☢️ │ └── serde 1.0.137
0/0 0/0 0/0 0/0 0/0 🔒 ├── serde_urlencoded 0.7.1
0/0 2/2 0/0 0/0 0/0 ☢️ │ ├── form_urlencoded 1.0.1
0/0 0/0 0/0 0/0 0/0 ❓ │ │ ├── matches 0.1.9
0/0 3/3 0/0 0/0 0/0 ☢️ │ │ └── percent-encoding 2.1.0
0/0 7/7 0/0 0/0 0/0 ☢️ │ ├── itoa 1.0.2
7/9 587/723 0/0 0/0 2/2 ☢️ │ ├── ryu 1.0.10
0/0 5/5 0/0 0/0 0/0 ☢️ │ └── serde 1.0.137
0/0 0/0 0/0 0/0 0/0 🔒 ├── temp-dir 0.1.11
0/0 0/0 0/0 0/0 0/0 🔒 ├── temp-file 0.1.7
0/0 0/0 0/0 0/0 0/0 ❓ └── url 2.2.2
0/0 2/2 0/0 0/0 0/0 ☢️ ├── form_urlencoded 1.0.1
0/0 0/0 0/0 0/0 0/0 ❓ ├── idna 0.2.3
0/0 0/0 0/0 0/0 0/0 ❓ │ ├── matches 0.1.9
0/0 0/0 0/0 0/0 0/0 🔒 │ ├── unicode-bidi 0.3.8
0/0 5/5 0/0 0/0 0/0 ☢️ │ │ └── serde 1.0.137
0/0 20/20 0/0 0/0 0/0 ☢️ │ └── unicode-normalization 0.1.19
0/0 0/0 0/0 0/0 0/0 🔒 │ └── tinyvec 1.6.0
0/0 5/5 0/0 0/0 0/0 ☢️ │ ├── serde 1.0.137
0/0 0/0 0/0 0/0 0/0 ❓ │ └── tinyvec_macros 0.1.0
0/0 0/0 0/0 0/0 0/0 ❓ ├── matches 0.1.9
0/0 3/3 0/0 0/0 0/0 ☢️ ├── percent-encoding 2.1.0
0/0 5/5 0/0 0/0 0/0 ☢️ └── serde 1.0.137
50/76 4670/5574 43/58 0/0 60/97
替代方案
请参阅 rust-webserver-comparison.md。
变更日志
- v0.3.2 - 将项目重命名为 'servlin'。
- v0.3.1 - 添加
Response::include_dir
。 - v0.3.0
- 添加
RequestBody::StaticBytes
。 - 添加
ResponseBody::StaticBytes
。 - 从
RequestBody
和ResponseBody
中移除impl From<&[u8]>
。
- 添加
- v0.2.0 - 使
print_log_response
更易于使用。 - v0.1.0 - 首次发布版本
待办事项
- 修复上述限制
- 支持设置了 Content-Length 而没有体(body)的 HEAD 响应。
- 更新
rust-webserver-comparison.md
- 添加缺失的数据
- 添加来自 https://www.arewewebyet.org/topics/frameworks/ 的其他服务器
- 重新排列
- 为每个网络服务器生成 geiger 报告
许可:MIT OR Apache-2.0
依赖项
~5–18MB
~226K SLoC