Hyper 库是 Rust 中的一个高效的、相对底层的 HTTP 库,可以用于构建 HTTP Client、HTTP Server,支持 HTTP/1、HTTP/2,同时也支持异步 Rust。这篇文章将学习 hyper
库的基本使用方法。
创建 HTTP Server
首先学习如何使用 Hyper
库构建一个基本的 HTTP Server,HTTP Client。
添加 Service
Service
用于定义 HTTP Server 如何响应 HTTP 请求,一个 Service
代表一个异步函数,该异步函数接受一个 Request
并返回一个 Future
。当该 Future
处理完成之后,它会得到一个 Response
(或者 error)。
Hyper 库提供了一个工具函数 service_fn
,它可以根据用户提供的一个函数来创建 Service
。如下提供了一个 hello
函数:
1 2 3
| async fn hello(_: Request<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, Infallible> { Ok(Response::new(Full::new(Bytes::from("Hello, World")))) }
|
当使用该函数作为 service 时,所有请求都会返回 200 响应,响应 body 会设置为 Hello, World!
,响应头等字段会自动设置。
启动 Server
接下来需要将 hello
service 添加到运行的 server 中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); let listener = TcpListener::bind(addr).await?;
loop { let (stream, _) = listener.accept().await?; let io = TokioIo::new(stream);
tokio::task::spawn(async move { if let Err(err) = http1::Builder::new() .serve_connection(io, service_fn(hello)) .await { println!("Error serving connection {:?}", err); } }); } }
|
创建 HTTP Client
接下来展示如何使用 Hpyer
库构建一个 HTTP client。在这个示例中,会给 http://httpbin.org/ip
发送一个 GET 请求,该站点会在 HTTP 响应中返回 client 的 IP 地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { let url = "http://httpbin.org/ip".parse::<hyper::Uri>()?; let host = url.host().expect("uri has no host"); let port = url.port_u16().unwrap_or(80); let address = format!("{}:{}", host, port);
let stream = TcpStream::connect(address).await?; let io = TokioIo::new(stream); let (mut sender, conn) = hyper::client::conn::http1::handshake(io).await?;
tokio::task::spawn(async move { if let Err(err) = conn.await { println!("Connection failed: {:?}", err); } });
let authority = url.authority().unwrap().clone();
let req = Request::builder() .uri(url) .header(hyper::header::HOST, authority.as_str()) .body(Empty::<Bytes>::new())?;
let mut res = sender.send_request(req).await?; println!("Response status: {}", res.status());
while let Some(next) = res.frame().await { let frame = next?; if let Some(chunk) = frame.data_ref() { io::stdout().write_all(chunk).await?; } } Ok(()) }
|
Reference