小言_互联网的博客

【Rust每周一库】hyper - 底层http库

582人阅读  评论(0)

现在说到写应用,网络框架肯定是必不可少的。今天就给大家简单介绍一下hyper。hyper是一个偏底层的http库,支持HTTP/1和HTTP/2,支持异步Rust,并且同时提供了服务端和客户端的API支持。很多同学可能觉得既然hyper是个偏底层的框架,那是不是就不需要去了解了呢?首先很多上层的框架,比如rocket、iron和reqwest底层都是基于hyper的。(关于Rust中各种网络开发框架,这里有个很全面的综述和比较。)所以如果在使用这些框架的时候遇到了一些问题,对hyper的了解肯定是有一定的帮助的。再者学习Rust的我们都是奔着成为大佬的路线去的,很难说不会有直接操作偏底层框架的需求。

Hello World

我们首先来实现一个简单的服务器端和客户端,支持最简单的GET操作。


服务器端

首先是依赖,除了hyper本身之外,我们还需要tokio的runtime去执行async函数


   
  1. [dependencies]
  2. hyper = "0.13"
  3. tokio = { version = "0.2", features = [ "full"] }

然后就是main.rs


   
  1. use std::{convert::Infallible, net::SocketAddr};
  2. use hyper::{Body, Request, Response, Server};
  3. use hyper::service::{make_service_fn, service_fn};
  4. // 返回200
  5. async fn handle(_: Request<Body>) -> Result<Response<Body>, Infallible> {
  6. Ok(Response:: new( "Hello, World!\n".into()))
  7. }
  8. #[tokio::main]
  9. async fn main() {
  10. let addr = SocketAddr::from(([ 127, 0, 0, 1], 3000));
  11. // 从handle创建一个服务
  12. let make_svc = make_service_fn(|_conn| async {
  13. Ok::<_, Infallible>(service_fn(handle))
  14. });
  15. let server = Server::bind(&addr).serve(make_svc);
  16. // 运行server
  17. if let Err(e) = server.await {
  18. eprintln!( "server error: {}", e);
  19. }
  20. }


客户端

依赖同服务器端


   
  1. use hyper::Client;
  2. use hyper::body::HttpBody as _;
  3. use tokio::io::{stdout, AsyncWriteExt as _};
  4. #[tokio::main]
  5. async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
  6. // 构建一个client,调用GET
  7. let client = Client:: new();
  8. let uri = "http://127.0.0.1:3000".parse()?;
  9. let mut resp = client.get(uri).await?;
  10. println!( "Response: {}", resp.status());
  11. // 将response(是个stream)输出到stdout
  12. while let Some(chunk) = resp.body_mut().data().await {
  13. stdout().write_all(&chunk?).await?;
  14. }
  15. Ok(())
  16. }

先启动服务端,然后启动客户端,就可以看到服务端成功相应客户端的GET请求啦~


   
  1. Response: 200 OK
  2. Hello, World!


更真实的例子

下面我们通过实现一个echo服务主要看一下服务器端如何进行路由,以及如何支持POST请求


服务器端

依赖


   
  1. [dependencies]
  2. hyper = "0.13"
  3. tokio = { version = "0.2", features = [ "full"] }
  4. futures-util = { version = "0.3", default-features = false }

代码


   
  1. use futures_util::TryStreamExt;
  2. use hyper::service::{make_service_fn, service_fn};
  3. use hyper::{Body, Method, Request, Response, Server, StatusCode};
  4. async fn echo(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
  5. let mut response = Response:: new(Body::empty());
  6. // 通过req.method()和req.uri().path()来识别方法和请求路径
  7. match (req.method(), req.uri().path()) {
  8. (&Method::GET, "/") => {
  9. *response.body_mut() = Body::from( "Try POSTing data to /echo");
  10. },
  11. (&Method::POST, "/echo") => {
  12. // 将POST的内容保持不变返回
  13. *response.body_mut() = req.into_body();
  14. },
  15. (&Method::POST, "/echo/uppercase") => {
  16. // 把请求stream中的字母都变成大写,并返回
  17. let mapping = req
  18. .into_body()
  19. .map_ok(|chunk| {
  20. chunk.iter()
  21. . map(| byte| byte.to_ascii_uppercase())
  22. .collect::<Vec<u8>>()
  23. });
  24. // 把stream变成body
  25. *response.body_mut() = Body::wrap_stream(mapping);
  26. },
  27. (&Method::POST, "/echo/reverse") => {
  28. // 这里需要完整的body,所以需要等待全部的stream并把它们变为bytes
  29. let full_body = hyper::body::to_bytes(req.into_body()).await?;
  30. // 把body逆向
  31. let reversed = full_body.iter()
  32. .rev()
  33. .cloned()
  34. .collect::<Vec<u8>>();
  35. *response.body_mut() = reversed.into();
  36. },
  37. _ => {
  38. *response.status_mut() = StatusCode::NOT_FOUND;
  39. },
  40. };
  41. Ok(response)
  42. }
  43. #[tokio::main]
  44. async fn main() {
  45. let addr = ([ 127, 0, 0, 1], 3000).into();
  46. let make_svc = make_service_fn(|_conn| async {
  47. Ok::<_, hyper::Error>(service_fn(echo))
  48. });
  49. let server = Server::bind(&addr).serve(make_svc);
  50. if let Err(e) = server.await {
  51. eprintln!( "server error: {}", e);
  52. }
  53. }


客户端

依赖和之前客户端一样。我们这里的代码以向/echo/reverse提交内容为echo的POST请求为例:


   
  1. use hyper::Client;
  2. use hyper::{Body, Method, Request};
  3. #[tokio::main]
  4. async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
  5. let req = Request::builder()
  6. .method(Method::POST)
  7. .uri( "http://127.0.0.1:3000/echo/reverse")
  8. .body(Body::from( "echo"))?;
  9. let client = Client:: new();
  10. let resp = client.request(req).await?;
  11. println!( "Response: {}", resp.status());
  12. println!( "{:?}", hyper::body::to_bytes(resp.into_body()).await.unwrap());
  13. Ok(())
  14. }

依次启动服务端和客户端,就可以看到服务端响应了客户端的POST请求啦~


   
  1. Response: 200 OK
  2. b "ohce"

好了,对hyper的介绍就到这里了。接下来就靠大家自己去深似海的网络编程世界中去摸索啦~


转载:https://blog.csdn.net/u012067469/article/details/103825786
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场