4个版本
0.1.3 | 2024年7月19日 |
---|---|
0.1.2 | 2024年7月19日 |
0.1.1 | 2024年7月19日 |
0.1.0 | 2024年7月19日 |
#149 in HTTP服务器
每月下载量 243
29KB
588 行
µHTTP 🦀🚀🌎
一个专为人类设计,小巧快速,用于在Rust中编写HTTP服务器的库
-
简单:受Go标准HTTP服务器库的启发 - 使用非异步处理程序来支持阻塞调用和简单的类型签名。
-
快速:高性能,多线程实现,可以与最快的Rust HTTP服务器竞争。
-
灵活:简单的接口,支持多种用例。它可以直接使用,也可以作为构建框架的基础。`Request`和`Response`类型实现了Rust的`Read`和`Write`接口,允许进行标准化和通用的交互。
用法
use std::io;
use std::io::Write;
use uhttp::http1::Server;
use uhttp::Request;
use uhttp::Response;
fn main() -> io::Result<()> {
Server::new(handler).listen("0.0.0.0:8080")
}
fn handler(req: Request, mut res: Response) -> io::Result<()> {
res.write_all(b"Hello World!")
res.write_header(200)
}
安装
在crates.io上提供,使用以下命令安装
cargo add uhttp
[dependencies]
uhttp = "0.*"
理念
该项目源于希望有一个使用愉快、最小化且可扩展的Rust HTTP服务器库。
大多数其他库使用异步Rust,这有助于处理IO密集型工作负载,但可能难以操作。此外,许多现有库使简单任务变得复杂,如将依赖项传递到处理程序或返回流式响应,在某些情况下甚至不完整。
µHTTP旨在提供一个经过时间考验的简单、可扩展且高效的HTTP服务器编写接口。
它具有合理的默认值,用于刷新响应、检测内容类型和自动帧编码。
使用标准库的`Read`和`Write`特质进行HTTP请求的读写,以最大化兼容性和提供熟悉性。
示例
请求正文
use std::io;
use std::io::Write;
use uhttp::http1::Server;
use uhttp::Request;
use uhttp::Response;
use uhttp::utils::body;
fn main() -> io::Result<()> {
Server::new(handler).listen("0.0.0.0:8080")
}
fn handler(mut req: Request, mut res: Response) -> io::Result<()> {
// Utility to read incoming bytes
let body_text = body::utf8(&mut req.body)?;
println!("{}", body_text);
res.write_header(201)
}
路由
URL作为`String`传递到处理程序中,并可用于将请求路径与路由匹配。您可以使用简单的if语句或第三方URL匹配库来处理路由。
待办事项:添加基本路由器
use std::io;
use std::io::Write;
use uhttp::http1::Server;
use uhttp::Request;
use uhttp::Response;
use uhttp::utils::body;
fn main() -> io::Result<()> {
Server::new(handler).listen("0.0.0.0:8080")
}
fn handler(mut req: Request, mut res: Response) -> io::Result<()> {
if req.method == "GET" && req.url == "/" {
return res.write_all("Hello World!")
}
if req.method == "POST" && req.url == "/api/echo" {
let bytes = body::bytes(&mut req.body)?;
return res.write_all(bytes)
}
res.write_header(404)
}
服务文件
use std::io;
use std::io::Write;
use std::fs;
use uhttp::http1::Server;
use uhttp::Request;
use uhttp::Response;
fn main() -> io::Result<()> {
http1::Server::new(handler).listen("0.0.0.0:8080")
}
fn handler(req: Request, mut res: Response) -> io::Result<()> {
let bytes = fs::read("/path/to/index.html")?;
res.write_all(bytes)
res.write_header(200)
}
常量
提供了一些常量,使响应更一致
use std::io;
use std::io::Write;
use uhttp::http1::Server;
use uhttp::Request;
use uhttp::Response;
use uhttp::c;
fn main() -> io::Result<()> {
Server::new(handler).listen("0.0.0.0:8080")
}
fn handler(req: Request, mut res: Response) -> io::Result<()> {
res.headers().set(c::headers::CONTENT_TYPE, c::content_type::TEXT_PLAIN);
res.write_all(b"Hello World!")
res.write_header(c::status::OK)
}
基准测试
在我的计算机上运行基准测试(Fedora Linux,AMD 7950x处理器,100GB RAM)且拥有100个并发连接
性能解释
显式设置头信息
显式设置 Content-Type
、Content-Length
或 Transfer-Encoding
可以提升性能,因为服务器不需要自动检测它们。
线程池 & May
uhttp 有两层,一个使用 May 协程库的非阻塞方式接受传入 TCP 套接字的 IO 层,并将请求转发到操作系统线程池进行处理
flowchart BT
main --> may1["may [1]"]
main --> may2["may [2]"]
main --> may3["may [3]"]
main --> may4["may [4]"]
may1 --> schedular
may2 --> schedular
may3 --> schedular
may4 --> schedular
schedular --> w1
schedular --> w2
schedular --> w3
schedular --> w4
schedular --> w5
schedular --> w6
schedular --> w7
schedular --> w0
subgraph may ["Socket Conn"]
may1
may2
may3
may4
end
subgraph OS Thread Pool
w1
w2
w3
w4
w5
w6
w7
w0["w..."]
end
尽管看到如此多的操作系统线程可能会让人感到震惊,但截至 2024 年,操作系统线程的开销已经显著低于历史水平,并且今天的应用程序可以使用成千上万的操作系统线程,对性能的影响很小。
虽然我非常想使用异步 Rust,但我发现它的使用并不舒适 - 因此,uhttp 在启动时启动一个大型线程池,并将每个 HTTP 请求的处理调度到线程池中其专用的操作系统线程。
这会略微影响启动时间,但没有任何有意义的运行时开销。
待办事项
- 为
Content-Encoding
提供gzip
和br
压缩工具 传输-编码:分块
- 服务器端事件(用此代替 WebSocket)
- HTTP/2
- 更多性能改进
范围之外
尽管可以随时提出 PR 以添加支持
- WebSocket
依赖项
~3–31MB
~430K SLoC