现在说到写应用,网络框架肯定是必不可少的。今天就给大家简单介绍一下hyper。hyper是一个偏底层的http库,支持HTTP/1和HTTP/2,支持异步Rust,并且同时提供了服务端和客户端的API支持。很多同学可能觉得既然hyper是个偏底层的框架,那是不是就不需要去了解了呢?首先很多上层的框架,比如rocket、iron和reqwest底层都是基于hyper的。(关于Rust中各种网络开发框架,这里有个很全面的综述和比较。)所以如果在使用这些框架的时候遇到了一些问题,对hyper的了解肯定是有一定的帮助的。再者学习Rust的我们都是奔着成为大佬的路线去的,很难说不会有直接操作偏底层框架的需求。
Hello World
我们首先来实现一个简单的服务器端和客户端,支持最简单的GET操作。
服务器端
首先是依赖,除了hyper本身之外,我们还需要tokio的runtime去执行async函数
-
[dependencies]
-
hyper =
"0.13"
-
tokio = { version =
"0.2", features = [
"full"] }
然后就是main.rs
-
use std::{convert::Infallible, net::SocketAddr};
-
use hyper::{Body, Request, Response, Server};
-
use hyper::service::{make_service_fn, service_fn};
-
-
// 返回200
-
async fn handle(_: Request<Body>) -> Result<Response<Body>, Infallible> {
-
Ok(Response::
new(
"Hello, World!\n".into()))
-
}
-
-
#[tokio::main]
-
async fn main() {
-
let addr = SocketAddr::from(([
127,
0,
0,
1],
3000));
-
-
// 从handle创建一个服务
-
let make_svc = make_service_fn(|_conn| async {
-
Ok::<_, Infallible>(service_fn(handle))
-
});
-
-
let server = Server::bind(&addr).serve(make_svc);
-
-
// 运行server
-
if let Err(e) = server.await {
-
eprintln!(
"server error: {}", e);
-
}
-
}
客户端
依赖同服务器端
-
use hyper::Client;
-
use hyper::body::HttpBody as _;
-
use tokio::io::{stdout, AsyncWriteExt as _};
-
-
#[tokio::main]
-
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
-
-
// 构建一个client,调用GET
-
let client = Client::
new();
-
let uri =
"http://127.0.0.1:3000".parse()?;
-
let mut resp = client.get(uri).await?;
-
println!(
"Response: {}", resp.status());
-
-
// 将response(是个stream)输出到stdout
-
while let Some(chunk) = resp.body_mut().data().await {
-
stdout().write_all(&chunk?).await?;
-
}
-
-
Ok(())
-
}
先启动服务端,然后启动客户端,就可以看到服务端成功相应客户端的GET请求啦~
-
Response:
200 OK
-
Hello, World!
更真实的例子
下面我们通过实现一个echo服务主要看一下服务器端如何进行路由,以及如何支持POST请求
服务器端
依赖
-
[dependencies]
-
hyper =
"0.13"
-
tokio = { version =
"0.2", features = [
"full"] }
-
futures-util = { version =
"0.3",
default-features =
false }
代码
-
use futures_util::TryStreamExt;
-
use hyper::service::{make_service_fn, service_fn};
-
use hyper::{Body, Method, Request, Response, Server, StatusCode};
-
-
async fn echo(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
-
let mut response = Response::
new(Body::empty());
-
-
// 通过req.method()和req.uri().path()来识别方法和请求路径
-
match (req.method(), req.uri().path()) {
-
(&Method::GET,
"/") => {
-
*response.body_mut() = Body::from(
"Try POSTing data to /echo");
-
},
-
(&Method::POST,
"/echo") => {
-
// 将POST的内容保持不变返回
-
*response.body_mut() = req.into_body();
-
},
-
(&Method::POST,
"/echo/uppercase") => {
-
// 把请求stream中的字母都变成大写,并返回
-
let mapping = req
-
.into_body()
-
.map_ok(|chunk| {
-
chunk.iter()
-
.
map(|
byte|
byte.to_ascii_uppercase())
-
.collect::<Vec<u8>>()
-
});
-
-
// 把stream变成body
-
*response.body_mut() = Body::wrap_stream(mapping);
-
},
-
(&Method::POST,
"/echo/reverse") => {
-
// 这里需要完整的body,所以需要等待全部的stream并把它们变为bytes
-
let full_body = hyper::body::to_bytes(req.into_body()).await?;
-
-
// 把body逆向
-
let reversed = full_body.iter()
-
.rev()
-
.cloned()
-
.collect::<Vec<u8>>();
-
-
*response.body_mut() = reversed.into();
-
},
-
_ => {
-
*response.status_mut() = StatusCode::NOT_FOUND;
-
},
-
};
-
-
Ok(response)
-
}
-
-
#[tokio::main]
-
async fn main() {
-
let addr = ([
127,
0,
0,
1],
3000).into();
-
-
let make_svc = make_service_fn(|_conn| async {
-
Ok::<_, hyper::Error>(service_fn(echo))
-
});
-
-
let server = Server::bind(&addr).serve(make_svc);
-
-
if let Err(e) = server.await {
-
eprintln!(
"server error: {}", e);
-
}
-
}
客户端
依赖和之前客户端一样。我们这里的代码以向/echo/reverse提交内容为echo的POST请求为例:
-
use hyper::Client;
-
use hyper::{Body, Method, Request};
-
-
#[tokio::main]
-
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
-
let req = Request::builder()
-
.method(Method::POST)
-
.uri(
"http://127.0.0.1:3000/echo/reverse")
-
.body(Body::from(
"echo"))?;
-
-
-
let client = Client::
new();
-
let resp = client.request(req).await?;
-
println!(
"Response: {}", resp.status());
-
println!(
"{:?}", hyper::body::to_bytes(resp.into_body()).await.unwrap());
-
-
Ok(())
-
}
依次启动服务端和客户端,就可以看到服务端响应了客户端的POST请求啦~
-
Response:
200 OK
-
b
"ohce"
好了,对hyper的介绍就到这里了。接下来就靠大家自己去深似海的网络编程世界中去摸索啦~
转载:https://blog.csdn.net/u012067469/article/details/103825786
查看评论