Rust HTTP/2协议库httpbis的使用:高效构建支持HTTP/2的双向流通信服务
Rust HTTP/2协议库httpbis的使用:高效构建支持HTTP/2的双向流通信服务
项目介绍
httpbis是一个基于tokio的Rust HTTP/2客户端和服务器实现。目前它被用作grpc-rust的实现基础。
示例服务器
查看源代码并执行命令:
cargo run --example server
服务器将在 https://localhost:8443/ 上可用。您需要任何支持HTTP/2的现代浏览器来打开页面(例如Firefox、Safari、Chrome)。
服务器仅通过HTTP/2工作,如果浏览器不发送HTTP/2前言,服务器将关闭连接。
示例客户端
cargo run --example client https://google.com/
结果如下:
:status: 302
cache-control: private
content-type: text/html; charset=UTF-8
referrer-policy: no-referrer
location: https://www.google.ru/?gfe_rd=cr&ei=mZQ4WZfaGISDZOzOktgO
content-length: 257
date: Thu, 08 Jun 2017 00:04:41 GMT
alt-svc: quic=":443"; ma=2592000; v="38,37,36,35"
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="https://www.google.ru/?gfe_rd=cr&amp;ei=mZQ4WZfaGISDZOzOktgO">here</A>.
</BODY></HTML>
完整示例
HTTP/2服务器示例代码
use httpbis::*;
use std::sync::Arc;
// 创建HTTP/2服务器
fn main() {
// 配置服务器参数
let mut server_conf = ServerConf::new();
server_conf.alpn_protocols = vec![b"h2".to_vec()]; // 仅支持HTTP/2
// 创建服务器
let mut server = ServerBuilder::new()
.conf(server_conf)
.service(Arc::new(HelloService))
.build()
.expect("Failed to build server");
// 添加TLS证书
server
.add_tls("localhost", include_bytes!("../test/cert.pem"), include_bytes!("../test/key.pem"))
.expect("Failed to add TLS");
// 绑定端口
server.bind_port(8443).expect("Failed to bind port");
println!("Server started at https://localhost:8443/");
server.wait();
}
// 简单的HTTP服务实现
struct HelloService;
impl Service for HelloService {
fn start_request(&self, _headers: Headers, _req: HttpStreamAfterHeaders) -> Response {
// 返回"Hello, World!"响应
Response::found_200_plain_text("Hello, World!")
}
}
HTTP/2客户端示例代码
use httpbis::*;
use std::sync::Arc;
fn main() {
// 创建客户端
let client = ClientBuilder::new()
.build("google.com", 443)
.expect("Failed to create client");
// 创建请求头
let mut headers = Headers::new();
headers.add(":method", "GET");
headers.add(":path", "/");
headers.add(":scheme", "https");
headers.add(":authority", "google.com");
headers.add("user-agent", "httpbis-example-client");
// 发送请求
let (resp_headers, resp_body) = client.start_request(headers, HttpStreamAfterHeaders::empty())
.expect("Failed to send request");
// 打印响应头
for (name, value) in resp_headers.iter() {
println!("{}: {}", name, value);
}
// 打印响应体
println!("\n{}", String::from_utf8_lossy(&resp_body.collect().unwrap()));
}
安装
作为库安装:
cargo add httpbis
或者在Cargo.toml中添加:
httpbis = "0.9.1"
特性
- 纯Rust实现的HTTP/2协议
- 基于tokio的高性能异步IO
- 支持TLS加密连接
- 双向流通信支持
- 可用于构建gRPC服务
许可证
MIT OR Apache-2.0
1 回复
Rust HTTP/2协议库httpbis的使用:高效构建支持HTTP/2的双向流通信服务
简介
httpbis
是一个纯 Rust 实现的 HTTP/2 协议库,它提供了构建支持 HTTP/2 双向流通信服务的能力。这个库专注于 HTTP/2 协议的核心实现,不包含高级 HTTP 框架功能,适合需要精细控制 HTTP/2 通信的开发者使用。
主要特性
- 纯 Rust 实现,无 C 依赖
- 完整的 HTTP/2 协议支持
- 双向流通信能力
- 支持服务器和客户端实现
- 高效的帧处理
- 可定制的流控制
使用方法
添加依赖
首先在 Cargo.toml
中添加依赖:
[dependencies]
httpbis = "0.9"
基本服务器示例
use httpbis::*;
use httpbis::server::*;
use futures::future::Future;
use std::env;
struct MyService;
impl Service for MyService {
fn start_request(&self, _headers: Headers, _req: HttpPartStream) -> Response {
// 创建一个响应流
let (sender, receiver) = futures::sync::mpsc::channel(1);
// 发送响应头
let headers = Headers::ok_200();
let resp = Response::headers_and_stream(headers, receiver);
// 在另一个线程中发送响应体
std::thread::spawn(move || {
sender.send(DataOrTrailers::data(b"Hello, HTTP/2!".to_vec())).wait().unwrap();
sender.send(DataOrTrailers::trailers(Headers::new())).wait().unwrap();
});
resp
}
}
fn main() {
// 创建服务器配置
let mut conf = ServerConf::new();
conf.alpn = Some(ServerAlpn::Require);
// 创建并运行服务器
let server = ServerBuilder::new
.set_port(8080)
.set_conf(conf)
.service(MyService)
.build()
.expect("Failed to start server");
println!("Server running on port 8080");
server.wait().expect("Server failed");
}
基本客户端示例
use httpbis::*;
use httpbis::Client;
use futures::future::Future;
fn main() {
// 创建客户端
let client = Client::new_plain(
"127.0.0.1",
8080,
Default::default(),
Default::default(),
).expect("Failed to create client");
// 创建请求头
let mut headers = Headers::new();
headers.add(":method", "GET");
headers.add(":path", "/");
headers.add(":scheme", "http");
headers.add(":authority", "127.0.0.1:8080");
// 发送请求
let (header, body) = client.start_request(headers, HttpPartStream::empty()).wait().expect("Request failed");
println!("Response headers: {:?}", header);
// 读取响应体
body.for_each(|chunk| {
match chunk {
DataOrTrailers::Data(data) => {
println!("Received data: {:?}", String::from_utf8_lossy(&data));
Ok(())
},
DataOrTrailers::Trailers(trailers) => {
println!("Received trailers: {:?}", trailers);
Ok(())
}
}
}).wait().expect("Failed to read response");
}
双向流通信示例
use httpbis::*;
use httpbis::server::*;
use futures::future::Future;
use futures::stream::Stream;
use futures::sync::mpsc;
struct EchoService;
impl Service for EchoService {
fn start_request(&self, _headers: Headers, req: HttpPartStream) -> Response {
// 创建响应流
let (sender, receiver) = mpsc::channel(1);
// 处理请求流
let process = req.for_each(move |chunk| {
match chunk {
DataOrTrailers::Data(data) => {
// 回显接收到的数据
sender.send(DataOrTrailers::data(data)).wait().unwrap();
Ok(())
},
DataOrTrailers::Trailers(_) => {
// 结束流
sender.send(DataOrTrailers::trailers(Headers::new())).wait().unwrap();
Ok(())
}
}
});
// 在后台处理请求流
std::thread::spawn(move || {
process.wait().unwrap();
});
// 返回响应
Response::headers_and_stream(Headers::ok_200(), receiver)
}
}
fn main() {
let server = ServerBuilder::new()
.set_port(8081)
.service(EchoService)
.build()
.expect("Failed to start server");
println!("Echo server running on port 8081");
server.wait().expect("Server failed");
}
高级配置
TLS 配置
use httpbis::*;
use std::path::Path;
fn configure_tls() {
let server = ServerBuilder::new()
.set_port(8443)
.set_tls(
ServerTlsOption::Tls(
// 证书链文件
Path::new("cert.pem"),
// 私钥文件
Path::new("key.pem"),
)
)
// ...其他配置
.build()
.expect("Failed to start server");
}
流控制配置
use httpbis::*;
fn configure_flow_control() {
let mut conf = ServerConf::new();
// 设置初始窗口大小 (默认 65535)
conf.initial_window_size = Some(128 * 1024);
// 设置最大帧大小 (默认 16384)
conf.max_frame_size = Some(32768);
let server = ServerBuilder::new()
.set_port(8080)
.set_conf(conf)
// ...其他配置
.build()
.expect("Failed to start server");
}
注意事项
httpbis
是一个底层库,不提供高级 HTTP 框架功能如路由、中间件等- 对于生产环境,建议使用更成熟的 HTTP/2 实现如
hyper
,除非有特殊需求 - HTTP/2 的某些高级特性如服务器推送需要手动实现
- 错误处理需要仔细考虑,特别是在流操作中
性能建议
- 重用客户端连接以避免握手开销
- 合理设置流控制窗口大小以平衡内存使用和吞吐量
- 对于大量小消息,考虑批处理以减少帧开销
- 使用适当的线程模型处理并发请求
完整示例:HTTP/2文件上传与下载服务
下面是一个完整的HTTP/2文件服务示例,包含文件上传和下载功能:
use httpbis::*;
use httpbis::server::*;
use futures::future::Future;
use futures::stream::Stream;
use futures::sync::mpsc;
use std::fs::File;
use std::io::Read;
use std::path::Path;
// 文件服务处理器
struct FileService {
upload_dir: String,
download_dir: String,
}
impl Service for FileService {
fn start_request(&self, headers: Headers, req: HttpPartStream) -> Response {
// 获取请求路径
let path = headers.get(":path").unwrap();
if path.starts_with("/upload") {
// 文件上传处理
self.handle_upload(req)
} else if path.starts_with("/download") {
// 文件下载处理
let filename = path.trim_start_matches("/download/");
self.handle_download(filename)
} else {
// 返回404响应
Response::not_found_404()
}
}
}
impl FileService {
// 处理文件上传
fn handle_upload(&self, req: HttpPartStream) -> Response {
let (sender, receiver) = mpsc::channel(1);
// 创建上传文件
let upload_path = format!("{}/uploaded_file_{}", self.upload_dir, std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs());
let mut file = File::create(&upload_path).unwrap();
// 处理上传流
let process = req.for_each(move |chunk| {
match chunk {
DataOrTrailers::Data(data) => {
// 写入文件
file.write_all(&data).unwrap();
Ok(())
},
DataOrTrailers::Trailers(_) => {
// 上传完成
sender.send(DataOrTrailers::trailers(Headers::new())).wait().unwrap();
Ok(())
}
}
});
// 在后台处理上传
std::thread::spawn(move || {
process.wait().unwrap();
});
// 返回响应
Response::headers_and_stream(Headers::ok_200(), receiver)
}
// 处理文件下载
fn handle_download(&self, filename: &str) -> Response {
let (sender, receiver) = mpsc::channel(1);
let file_path = format!("{}/{}", self.download_dir, filename);
// 在另一个线程中读取并发送文件
std::thread::spawn(move || {
let mut file = File::open(&file_path).unwrap();
let mut buffer = vec![0; 1024 * 8]; // 8KB缓冲区
loop {
let bytes_read = file.read(&mut buffer).unwrap();
if bytes_read == 0 {
break;
}
sender.send(DataOrTrailers::data(buffer[..bytes_read].to_vec()))
.wait()
.unwrap();
}
// 发送结束标记
sender.send(DataOrTrailers::trailers(Headers::new())).wait().unwrap();
});
// 返回响应
Response::headers_and_stream(Headers::ok_200(), receiver)
}
}
fn main() {
// 创建文件服务
let file_service = FileService {
upload_dir: "uploads".to_string(),
download_dir: "downloads".to_string(),
};
// 创建并启动服务器
let server = ServerBuilder::new()
.set_port(8080)
.service(file_service)
.build()
.expect("Failed to start server");
println!("HTTP/2文件服务运行在端口8080");
server.wait().expect("服务器运行失败");
}
这个完整示例展示了如何使用httpbis
构建一个支持HTTP/2的文件上传下载服务,包含了以下功能:
- 处理文件上传请求,将上传的文件保存到指定目录
- 处理文件下载请求,将文件分块发送给客户端
- 使用HTTP/2的流特性高效传输大文件
- 多线程处理避免阻塞主线程
要使用这个服务,客户端可以发送HTTP/2请求到:
/upload
路径上传文件/download/{filename}
路径下载文件