跳过正文

http/http_body

··4783 字
Rust Rust-Crate
目录
rust crate - 这篇文章属于一个选集。
§ 16: 本文

http/http_body crate 是公共的 http 和 body 定义,在 tokio 系列的 HTTP 库,如 hyper/axum/reqwest 中得到广泛应用,这些 crate 通过 import + pub use 的方式将 http/http_body 的类型导入到自己 crate 中来使用。比如 reqwest::method 实际是 http::method , 但是也有一些是封装,例如 reqwest::Request/reqwest::Response 是 http::Requesthttp::Response 的封装。

1 request
#

http::request module 包含三个类型:

  1. struct Request
  2. struct Parts
  3. struct Builder

http::request::Request%3CT%3E 是泛型类型,T 对应 body 的数据类型:

  1. Request<()>:未设置 body 的请求,具有创建 Builder 的一系列函数,后续可以使用 Builder 的body()方法来设置 body 并返回对应的 Request<T> 类型对象;
  2. Request<T> :设置 body 内容为 T 类型的请求。T 没有限界,所以默认是 Sized。
// impl Request<()> 实现的关联函数
// 返回各种类型的 Builder,如:
//
// Request::builder().uri("https://www.rust-lang.org/")
// Request::delete("https://www.rust-lang.org/")
//     .body(())
//     .unwrap();

pub fn builder() -> Builder
pub fn get<T>(uri: T) -> Builder where Uri: TryFrom<T>, <Uri as TryFrom<T>>::Error: Into<Error>
pub fn put<T>(uri: T) -> Builder where Uri: TryFrom<T>, <Uri as TryFrom<T>>::Error: Into<Error>
pub fn post<T>(uri: T) -> Builder where Uri: TryFrom<T>, <Uri as TryFrom<T>>::Error: Into<Error>
pub fn delete<T>(uri: T) -> Builder where Uri: TryFrom<T>, <Uri as TryFrom<T>>::Error: Into<Error>
pub fn options<T>(uri: T) -> Builder where Uri: TryFrom<T>, <Uri as TryFrom<T>>::Error: Into<Error>
pub fn head<T>(uri: T) -> Builder where Uri: TryFrom<T>, <Uri as TryFrom<T>>::Error: Into<Error>
pub fn connect<T>(uri: T) -> Builder where Uri: TryFrom<T>, <Uri as TryFrom<T>>::Error: Into<Error>
pub fn patch<T>(uri: T) -> Builder where Uri: TryFrom<T>, <Uri as TryFrom<T>>::Error: Into<Error>
pub fn trace<T>(uri: T) -> Builder where Uri: TryFrom<T>, <Uri as TryFrom<T>>::Error: Into<Error>

// 以下是 impl<T> Request<T> 的方法
// 创建 Request<T> 类型对象时需要传入 body,一个 Request 由 Parts + body 组成。
//
// let request = Request::new("hello world");
// assert_eq!(*request.method(), Method::GET);
// assert_eq!(*request.body(), "hello world");

pub fn new(body: T) -> Request<T> // 创建一个 HTTP 1.1 GET / 请求
pub fn from_parts(parts: Parts, body: T) -> Request<T>

pub fn method(&self) -> &Method
pub fn method_mut(&mut self) -> &mut Method
pub fn uri(&self) -> &Uri
pub fn uri_mut(&mut self) -> &mut Uri
pub fn version(&self) -> Version
pub fn version_mut(&mut self) -> &mut Version
pub fn headers(&self) -> &HeaderMap<HeaderValue>
pub fn headers_mut(&mut self) -> &mut HeaderMap<HeaderValue>

pub fn extensions(&self) -> &Extensions
pub fn extensions_mut(&mut self) -> &mut Extensions
// let mut request: Request<()> = Request::default();
// request.extensions_mut().insert("hello");
// assert_eq!(request.extensions().get(), Some(&"hello"));

pub fn body(&self) -> &T
pub fn body_mut(&mut self) -> &mut T
pub fn into_body(self) -> T

// 返回 http reqeust Parts 和 body 内容
pub fn into_parts(self) -> (Parts, T)

pub fn map<F, U>(self, f: F) -> Request<U>where F: FnOnce(T) -> U,

通过 http::request::Builder 的方法可以设置 method/uri/version/header/extension/body():

  • body<T>(self, body: T) 消耗 Builder,使用传入的 body 内容,返回一个 Reuest。
// impl Builder 的方法

pub fn new() -> Builder

pub fn method<T>(self, method: T) -> Builder
   where Method: TryFrom<T>, <Method as TryFrom<T>>::Error: Into<Error>
pub fn method_ref(&self) -> Option<&Method>

pub fn uri<T>(self, uri: T) -> Builder
   where Uri: TryFrom<T>, <Uri as TryFrom<T>>::Error: Into<Error>
pub fn uri_ref(&self) -> Option<&Uri>

pub fn version(self, version: Version) -> Builder
pub fn version_ref(&self) -> Option<&Version>

pub fn header<K, V>(self, key: K, value: V) -> Builder where
    HeaderName: TryFrom<K>,
    <HeaderName as TryFrom<K>>::Error: Into<Error>,
    HeaderValue: TryFrom<V>,
    <HeaderValue as TryFrom<V>>::Error: Into<Error>
pub fn headers_ref(&self) -> Option<&HeaderMap<HeaderValue>>
pub fn headers_mut(&mut self) -> Option<&mut HeaderMap<HeaderValue>>

// 为 Request 关联一个 Extension<T>
pub fn extension<T>(self, extension: T) -> Builder
    where T: Clone + Any + Send + Sync + 'static
pub fn extensions_ref(&self) -> Option<&Extensions>
pub fn extensions_mut(&mut self) -> Option<&mut Extensions>

// body() 消耗 Builder,用传入的 body 返回一个 Request<T>
pub fn body<T>(self, body: T) -> Result<Request<T>>

http::request::Parts 是 Request 除 body 外的信息(类似的还有 http::response::Parts 表示 Response 除 body 外的内容):

pub struct Parts {
    pub method: Method,
    pub uri: Uri,
    pub version: Version,
    pub headers: HeaderMap<HeaderValue>,
    pub extensions: Extensions,
    /* private fields */
}

示例:

let mut request: Request<String> = Request::default();
assert!(request.body().is_empty());
request.body_mut().push_str("hello world");
assert!(!request.body().is_empty());

use http::{Request, Response};

// Request::builder() 创建的是 Request<()> 类型对象,所以 request.body(()) 传入的是 ();
let mut request = Request::builder()
    .uri("https://www.rust-lang.org/")
    .header("User-Agent", "my-awesome-agent/1.0");
if needs_awesome_header() {
    request = request.header("Awesome", "yes");
}

let response = send(request.body(()).unwrap());
fn send(req: Request<()>) -> Response<()> {
    // ...
}

// Inspecting a request to see what was sent.
use http::{Request, Response, StatusCode};

fn respond_to(req: Request<()>) -> http::Result<Response<()>> { // T 都是 () 类型
    if req.uri() != "/awesome-url" {
        return Response::builder()
            .status(StatusCode::NOT_FOUND)
            .body(())
    }

    let has_awesome_header = req.headers().contains_key("Awesome");
    let body = req.body();
    // ...
}

// Deserialize a request of bytes via json:
use http::Request;
use serde::de;

fn deserialize<T>(req: Request<Vec<u8>>) -> serde_json::Result<Request<T>>
    where for<'de> T: de::Deserialize<'de>,
{
    let (parts, body) = req.into_parts();
    let body = serde_json::from_slice(&body)?;
    Ok(Request::from_parts(parts, body))
}

// Or alternatively, serialize the body of a request to json
use http::Request;
use serde::ser;

fn serialize<T>(req: Request<T>) -> serde_json::Result<Request<Vec<u8>>>
    where T: ser::Serialize,
{
    let (parts, body) = req.into_parts();
    let body = serde_json::to_vec(&body)?;
    Ok(Request::from_parts(parts, body))
}

2 response
#

http::response module 包含:

  1. Response struct

  2. Parts struct

  3. Builder struct

    http::response::Response%3CT%3E 是泛型类型,T 对应 body 的数据类型:

  4. Response<()>:未设置 body 的请求,具有创建 Builder 的一系列函数,后续可以使用 Builder 的body() 方法来设置 body 并返回对应的 Response<T> 类型对象;

  5. Response<T> :设置 body 内容为 T 类型的响应。T 没有限界,所以默认是 Sized。

// 创建一个 Response Builder
impl Response<()>
pub fn builder() -> Builder

// 直接创建 Response,需要在 new() 创建时传入 body
impl<T> Response<T>
pub fn new(body: T) -> Response<T>
pub fn from_parts(parts: Parts, body: T) -> Response<T>

pub fn status(&self) -> StatusCode
pub fn status_mut(&mut self) -> &mut StatusCode
pub fn version(&self) -> Version
pub fn version_mut(&mut self) -> &mut Version
pub fn headers(&self) -> &HeaderMap<HeaderValue>
pub fn headers_mut(&mut self) -> &mut HeaderMap<HeaderValue>
pub fn extensions(&self) -> &Extensions
pub fn extensions_mut(&mut self) -> &mut Extensions
pub fn body(&self) -> &T
pub fn body_mut(&mut self) -> &mut T
pub fn into_body(self) -> T
pub fn into_parts(self) -> (Parts, T)
pub fn map<F, U>(self, f: F) -> Response<U> where F: FnOnce(T) -> U,

http::response::Builder 对象:

impl Builder

pub fn new() -> Builder

pub fn status<T>(self, status: T) -> Builderwhere
    StatusCode: TryFrom<T>,
    <StatusCode as TryFrom<T>>::Error: Into<Error>

pub fn version(self, version: Version) -> Builder

pub fn header<K, V>(self, key: K, value: V) -> Builderwhere
    HeaderName: TryFrom<K>,
    <HeaderName as TryFrom<K>>::Error: Into<Error>,
    HeaderValue: TryFrom<V>,
    <HeaderValue as TryFrom<V>>::Error: Into<Error>

pub fn headers_ref(&self) -> Option<&HeaderMap<HeaderValue>>
pub fn headers_mut(&mut self) -> Option<&mut HeaderMap<HeaderValue>>

// Response 可以关联 Extensions<T>
pub fn extension<T>(self, extension: T) -> Builderwhere
    T: Clone + Any + Send + Sync + 'static
pub fn extensions_ref(&self) -> Option<&Extensions>
pub fn extensions_mut(&mut self) -> Option<&mut Extensions>

// 消耗 Builder,使用传入的 T 类型 body,返回一个 Response<T>
pub fn body<T>(self, body: T) -> Result<Response<T>>

http::response::Parts 表示除了 body 外的 HTTP 响应内容:

pub struct Parts {
    pub status: StatusCode,
    pub version: Version,
    pub headers: HeaderMap<HeaderValue>,
    pub extensions: Extensions,
    /* private fields */
}

示例:

pub struct Response<T> { /* private fields */ }

use http::{Request, Response, StatusCode};

fn respond_to(req: Request<()>) -> http::Result<Response<()>> {
    let mut builder = Response::builder()
        .header("Foo", "Bar")
        .status(StatusCode::OK);

    if req.headers().contains_key("Another-Header") {
        builder = builder.header("Another-Header", "Ack");
    }

    builder.body(()) // Builder 的 body() 方法返回一个 Response<T> 对象
}

fn not_found(_req: Request<()>) -> http::Result<Response<()>> {
    Response::builder()
        .status(StatusCode::NOT_FOUND)
        .body(())
}

// 解序列化
fn deserialize<T>(res: Response<Vec<u8>>) -> serde_json::Result<Response<T>>
    where for<'de> T: de::Deserialize<'de>,
{
    let (parts, body) = res.into_parts();
    let body = serde_json::from_slice(&body)?;
    Ok(Response::from_parts(parts, body))
}

3 header #

http::header module 提供了三个类型:

HeaderMap
HTTP headers 集合
HeaderName
HTTP header field name
HeaderValue
HTTP header field value

HeaderName 提供了大小写不敏感的 header field name(内部会进行小写归一化),以加快比较和处理。

HeaderName:代表一个 HTTP header name,在 HeaderMap 的相关方法中使用:

  • from_XX() 方法将传入的 key name 转换为 HTTP 标准 key name
pub struct HeaderName { /* private fields */ }

impl HeaderName
// 创建 HeaderName
pub fn from_bytes(src: &[u8]) -> Result<HeaderName, InvalidHeaderName>
pub fn from_lowercase(src: &[u8]) -> Result<HeaderName, InvalidHeaderName>
pub const fn from_static(src: &'static str) -> HeaderName
pub fn as_str(&self) -> &str

// Parsing a lower case header
let hdr = HeaderName::from_lowercase(b"content-length").unwrap();
assert_eq!(CONTENT_LENGTH, hdr);
// Parsing a header that contains uppercase characters
assert!(HeaderName::from_lowercase(b"Content-Length").is_err());

// Parsing a standard header
let hdr = HeaderName::from_static("content-length");
assert_eq!(CONTENT_LENGTH, hdr);

// Parsing a custom header
let CUSTOM_HEADER: &'static str = "custom-header";

let a = HeaderName::from_lowercase(b"custom-header").unwrap();
let b = HeaderName::from_static(CUSTOM_HEADER);
assert_eq!(a, b);

http::header module 提供了大量标准的 HeaderName 常量定义:

pub const ACCEPT: HeaderName;
pub const RANGE: HeaderName;
// ...

HeaderValue:

let val = HeaderValue::from_static("hello");
assert_eq!(val, "hello");

let val = HeaderValue::from_str("hello").unwrap();
assert_eq!(val, "hello");

let val = HeaderValue::from_bytes(b"hello\xfa").unwrap();
assert_eq!(val, &b"hello\xfa"[..]);

HeaderMap 是高度优化的 HTTP Header 集合,内部使用 multimap 解构,一个 header field 可以有多个 header value,它的 APIs 接口和 HashMap 类似。

  • T 代表 header value 值类型,默认为 HeaderValue;
  • 将 HeaderName 关联到 HeaderValue
  • 一个 key 可以通过 append() 方法添加多个 value,后续通过 get_all() 获得该 key 的所有 value;
pub struct HeaderMap<T = HeaderValue> { /* private fields */ }

impl HeaderMap
pub fn new() -> HeaderMap

impl<T> HeaderMap<T>
pub fn with_capacity(capacity: usize) -> HeaderMap<T>
pub fn try_with_capacity( capacity: usize ) -> Result<HeaderMap<T>, MaxSizeReached>

pub fn len(&self) -> usize
pub fn keys_len(&self) -> usize
pub fn is_empty(&self) -> bool
pub fn clear(&mut self)

pub fn capacity(&self) -> usize
pub fn reserve(&mut self, additional: usize)
pub fn try_reserve(&mut self, additional: usize) -> Result<(), MaxSizeReached>

// 获得 header 对应的 value,这里的 key 可以是任何实现 AsHeaderName 的类型
pub fn get<K>(&self, key: K) -> Option<&T> where K: AsHeaderName
pub fn get_mut<K>(&mut self, key: K) -> Option<&mut T> where K: AsHeaderName
pub fn get_all<K>(&self, key: K) -> GetAll<'_, T> where K: AsHeaderName
pub fn contains_key<K>(&self, key: K) -> bool where K: AsHeaderName

// 支持迭代
pub fn iter(&self) -> Iter<'_, T>
pub fn iter_mut(&mut self) -> IterMut<'_, T>

pub fn keys(&self) -> Keys<'_, T>
pub fn values(&self) -> Values<'_, T>
pub fn values_mut(&mut self) -> ValuesMut<'_, T>

pub fn drain(&mut self) -> Drain<'_, T>

// 支持和 HashMap 类似的 Entry 修改机制
pub fn entry<K>(&mut self, key: K) -> Entry<'_, T> where K: IntoHeaderName
pub fn try_entry<K>( &mut self, key: K) -> Result<Entry<'_, T>, InvalidHeaderName>
   where K: AsHeaderName

// 添加 key-value,一个 key 可以通过 append() 添加多个 value
pub fn insert<K>(&mut self, key: K, val: T) -> Option<T> where K: IntoHeaderName
pub fn try_insert<K>( &mut self, key: K, val: T) -> Result<Option<T>, MaxSizeReached>
   where K: IntoHeaderName
pub fn append<K>(&mut self, key: K, value: T) -> bool where K: IntoHeaderName
pub fn try_append<K>( &mut self, key: K, value: T) -> Result<bool, MaxSizeReached>
   where K: IntoHeaderName

pub fn remove<K>(&mut self, key: K) -> Option<T> where K: AsHeaderName

// HeaderMap 实现了 Index trait,可以使用 headers[key] 操作
impl<K, T> Index<K> for HeaderMap<T> where K: AsHeaderName
  fn index(&self, index: K) -> &T
  type Output = T

HeaderMap 实现了几个 Extend/FromIterators/TryFrom trait,可以快速创建 HeaderMap:

impl<T> Extend<(HeaderName, T)> for HeaderMap<T>
fn extend<I: IntoIterator<Item = (HeaderName, T)>>(&mut self, iter: I)

impl<T> Extend<(Option<HeaderName>, T)> for HeaderMap<T>
fn extend<I: IntoIterator<Item = (Option<HeaderName>, T)>>(&mut self, iter: I)

impl<T> FromIterator<(HeaderName, T)> for HeaderMap<T>
fn from_iter<I>(iter: I) -> Self where I: IntoIterator<Item = (HeaderName, T)>,

impl<'a, K, V, T> TryFrom<&'a HashMap<K, V>> for HeaderMap<T>where
    K: Eq + Hash,
    HeaderName: TryFrom<&'a K>,
    <HeaderName as TryFrom<&'a K>>::Error: Into<Error>,
    T: TryFrom<&'a V>,
    T::Error: Into<Error>,

示例:

let mut headers = HeaderMap::new();
headers.insert(HOST, "example.com".parse().unwrap()); // parse() 将 &str 转换为 HeaderValue
headers.insert(CONTENT_LENGTH, "123".parse().unwrap());
assert!(headers.contains_key(HOST));
assert!(!headers.contains_key(LOCATION));

assert_eq!(headers[HOST], "example.com"); // index 操作
headers.remove(HOST);
assert!(!headers.contains_key(HOST));

let mut map = HeaderMap::new();
assert!(map.get("host").is_none());
map.insert(HOST, "hello".parse().unwrap());
assert_eq!(map.get(HOST).unwrap(), &"hello");
assert_eq!(map.get("host").unwrap(), &"hello");
map.append(HOST, "world".parse().unwrap());
assert_eq!(map.get("host").unwrap(), &"hello");

// 一个 key 可以有多个 value
let mut map = HeaderMap::new();
map.insert(HOST, "hello".parse().unwrap());
map.append(HOST, "goodbye".parse().unwrap());
let view = map.get_all("host");
let mut iter = view.iter();
assert_eq!(&"hello", iter.next().unwrap());
assert_eq!(&"goodbye", iter.next().unwrap());
assert!(iter.next().is_none());

4 method
#

http::method module 提供了 http Method struct 定义,它包含一些标准的 http method 常量定义:

pub struct Method(/* private fields */);

// Method 关联的常量
impl Method
pub const GET: Method = _
pub const POST: Method = _
pub const PUT: Method = _
pub const DELETE: Method = _
pub const HEAD: Method = _
pub const OPTIONS: Method = _
pub const CONNECT: Method = _
pub const PATCH: Method = _
pub const TRACE: Method = _

// 创建 Method
pub fn from_bytes(src: &[u8]) -> Result<Method, InvalidMethod>
pub fn is_safe(&self) -> bool
pub fn is_idempotent(&self) -> bool
pub fn as_str(&self) -> &str

示例:

use http::Method;
assert_eq!(Method::GET, Method::from_bytes(b"GET").unwrap());
assert!(Method::GET.is_idempotent());
assert_eq!(Method::POST.as_str(), "POST");

5 status
#

http::status module 提供了 StatusCode struct 类型和标准 HTTP status 常量:

pub struct StatusCode(/* private fields */);

impl StatusCode

// 创建 StatusCode
pub fn from_u16(src: u16) -> Result<StatusCode, InvalidStatusCode>
pub fn from_bytes(src: &[u8]) -> Result<StatusCode, InvalidStatusCode>

pub fn as_u16(&self) -> u16
pub fn as_str(&self) -> &str
pub fn canonical_reason(&self) -> Option<&'static str>
pub fn is_informational(&self) -> bool
pub fn is_success(&self) -> bool
pub fn is_redirection(&self) -> bool
pub fn is_client_error(&self) -> bool
pub fn is_server_error(&self) -> bool

// 标准 HTTP StatusCode:
pub const CONTINUE: StatusCode = _
pub const SWITCHING_PROTOCOLS: StatusCode = _
pub const PROCESSING: StatusCode = _
pub const OK: StatusCode = _
//..

示例:

use http::StatusCode;

assert_eq!(StatusCode::from_u16(200).unwrap(), StatusCode::OK);
assert_eq!(StatusCode::NOT_FOUND.as_u16(), 404);
assert!(StatusCode::OK.is_success());

6 extensions
#

struct http::Extensions 是在 Request 和 Response 中使用的, 使用特定类型来保存数据。具有 get/insert/remove() 方法,它们都是根据泛型类型来获取或设置值的。

let mut ext = Extensions::new();
assert!(ext.insert(5i32).is_none());
assert!(ext.insert(4u8).is_none());
assert_eq!(ext.insert(9i32), Some(5i32));

let mut ext = Extensions::new();
assert!(ext.get::<i32>().is_none());
ext.insert(5i32);
assert_eq!(ext.get::<i32>(), Some(&5i32));

let mut ext = Extensions::new();
ext.insert(5i32);
assert_eq!(ext.remove::<i32>(), Some(5i32));
assert!(ext.get::<i32>().is_none());

// http::Request/Response 类型均可以保存 Extentions
let mut request: Request<()> = Request::default();
request.extensions_mut().insert("hello"); // &str 类型
assert_eq!(request.extensions().get(), Some(&"hello"));

7 uri
#

uri module 提供了 Uri/Parts/Port/Schema 等类型, Uri 并不等于 URL, Uri 可能只包含 Full URL 的部分内容.

Uri:

// abc://username:[email protected]:123/path/data?key=value&key2=value2#fragid1
// |-|   |-------------------------------||--------| |-------------------| |-----|
//  |                  |                       |               |              |
// scheme          authority                 path            query         fragment

use http::Uri;

let uri = "/foo/bar?baz".parse::<Uri>().unwrap();
assert_eq!(uri.path(), "/foo/bar");
assert_eq!(uri.query(), Some("baz"));
assert_eq!(uri.host(), None);

let uri = "https://www.rust-lang.org/install.html".parse::<Uri>().unwrap();
assert_eq!(uri.scheme_str(), Some("https"));
assert_eq!(uri.host(), Some("www.rust-lang.org"));
assert_eq!(uri.path(), "/install.html");

8 http_body/http_body_util crate
#

http crate 的 Request<T> 和 Response<T> 都是泛型类型,T 表示 HTTP Body 值类型。

http_body crate 提供了 async HTTP 中 Request<B> 或 Response<B> 的 B 要实现的 Body trait ,每次调用 poll_frame() 方法时返回一个 Frame<Self::Data> 类型对象, 其中 Data是实现 bytes::Buf trait 类型。

http_body::Frame<T> 可以用于保存 Data(类型为 T) 或 trailers headers(二选一),trailers 通常用在 HTTP/2.0 协议中。

pub trait Body {
    type Data: Buf; // bytes::Buf trait 类型,只读(内部包含读指针)。
    type Error;

    // Required method
    // 返回一个 http_body::Frame<Self.Data> 类型值数据
    fn poll_frame(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>
    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>>;

    // Provided methods
    fn is_end_stream(&self) -> bool { ... }
    fn size_hint(&self) -> SizeHint { ... }
}

// http_body::Frame 可以保存 body data(类型为 T)或 trailers map(类型为 HeaderMap)(二选一)
pub struct Frame<T> { /* private fields */ }
// 1. 用 T 类型 body buf 创建一个 Frame
pub fn data(buf: T) -> Self
// 2. 用 HeaderMap 创建一个 Frame
pub fn trailers(map: HeaderMap) -> Self

pub fn map_data<F, D>(self, f: F) -> Frame<D> where F: FnOnce(T) -> D

// 是否保存的是 data
pub fn is_data(&self) -> bool
// 返回 Frame 中的 Data
pub fn into_data(self) -> Result<T, Self>
pub fn data_ref(&self) -> Option<&T>
pub fn data_mut(&mut self) -> Option<&mut T>

// 是否保存的是 trailers headers
pub fn is_trailers(&self) -> bool
// 返回 Frame 中的 trailers
pub fn into_trailers(self) -> Result<HeaderMap, Self>
pub fn trailers_ref(&self) -> Option<&HeaderMap>
pub fn trailers_mut(&mut self) -> Option<&mut HeaderMap>

当 B 类型实现 http_body::Body trait 时,Request<B>/Response<B> 和 String 类型也实现了 http_body::Body trait:

impl Body for String
type Data = Bytes // 返回 bytes::Bytes struct 类型
type Error = Infallible
fn poll_frame(
    self: Pin<&mut Self>,
    _cx: &mut Context<'_>
) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>>


// B 需要实现 http_body::Body trait
impl<B: Body> Body for Request<B>
type Data = <B as Body>::Data
type Error = <B as Body>::Error
fn poll_frame(
    self: Pin<&mut Self>,
    cx: &mut Context<'_>
) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>>

impl<B: Body> Body for Response<B>
type Data = <B as Body>::Data
type Error = <B as Body>::Error
fn poll_frame(
    self: Pin<&mut Self>,
    cx: &mut Context<'_>
) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>>

http_body_util crate 提供了实现 http_body::Body trait 的 Full<T>/Empty<T> 类型:

  • Empty<D> :空数据;
  • Full<D>: 返回一个 D 类型对象的数据,实现的 http_body::Body 的 Data 为 D 类型值,D 需要实现 bytes::Buf trait ;
pub struct Empty<D> { /* private fields */ }
impl<D> Empty<D>
pub fn new() -> Self // Create a new Empty.

pub struct Full<D> { /* private fields */ }
// Full 实现了各种 From trait,可以从 &[u8]/&str/Bytes/String/Vec<u8> 等创建 Full<D>
impl<D> From<&'static [u8]> for Full<D> where D: Buf + From<&'static [u8]>
impl<D> From<&'static str> for Full<D> where D: Buf + From<&'static str>
impl<D> From<Bytes> for Full<D> where D: Buf + From<Bytes>
impl<D, B> From<Cow<'static, B>> for Full<D>
  where D: Buf + From<&'static B> + From<B::Owned>, B: ToOwned + ?Sized
impl<D> From<String> for Full<D> where D: Buf + From<String>
impl<D> From<Vec<u8>> for Full<D> where D: Buf + From<Vec<u8>>

// 示例
use http::HeaderMap;
use http_body_util::{Full, BodyExt};
use bytes::Bytes;

async fn main() {
let (tx, rx) = tokio::sync::oneshot::channel::<HeaderMap>();

// Full 实现了 http_body::Body trait
let body = Full::<Bytes>::from("Hello, World!")
    // add trailers via a future
    .with_trailers(async move {
        match rx.await {
            Ok(trailers) => Some(Ok(trailers)),
            Err(_err) => None,
        }
    });

// compute the trailers in the background
tokio::spawn(async move {
    let _ = tx.send(compute_trailers().await);
});

async fn compute_trailers() -> HeaderMap {
    // ...
}

http_body_util crate 还为 http_body::Body trait 定义了扩展 trait http_body_util::BodyExt :

  1. 提供了便于使用的 frame() 方法, 可以在 while 循环中连续调用,返回实现 Future 的 Frame ,可以流式迭代。
  2. 提供了 into_data_stream() 方法,将 Body::Data 数据转换为 BodyDataStream ,它实现了 futures::stream::Stream trait,通过使用 futures::stream::StreamExt 的 next() 等方法,可以流式迭代;
  3. 提供了 collect() 方法,可以一次收集所有 Body 数据,而 frame() 需要持续迭代调用。
  4. 所有实现了 http_body::Body trait 的对象均实现 BodyExt。
pub trait BodyExt: Body {
    // Provided methods
    // Frame 实现了 Future,返回 Option,当没有数据时返回 None,故可以 while-let 迭代。
    fn frame(&mut self) -> Frame<'_, Self>
       where Self: Unpin { ... }

    fn map_frame<F, B>(self, f: F) -> MapFrame<Self, F>
       where Self: Sized, F: FnMut(Frame<Self::Data>) -> Frame<B>, B: Buf { ... }
    fn map_err<F, E>(self, f: F) -> MapErr<Self, F>
       where Self: Sized, F: FnMut(Self::Error) -> E { ... }
    fn boxed(self) -> BoxBody<Self::Data, Self::Error>
       where Self: Sized + Send + Sync + 'static { ... }
    fn boxed_unsync(self) -> UnsyncBoxBody<Self::Data, Self::Error>
       where Self: Sized + Send + 'static { ... }

    fn collect(self) -> Collect<Self>
       where Self: Sized { ... }

    fn with_trailers<F>(self, trailers: F) -> WithTrailers<Self, F>
       where Self: Sized, F: Future<Output = Option<Result<HeaderMap, Self::Error>>> { ... }
    fn into_data_stream(self) -> BodyDataStream<Self>
       where Self: Sized { ... }
}

// Frame 实现了 Future,可以 .await, 返回 http_body::Body::Data 数据。
pub struct Frame<'a, T: ?Sized>(/* private fields */);
impl<'a, T: Body + Unpin + ?Sized> Future for Frame<'a, T>
type Output = Option<Result<Frame
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output>

// 所有实现了 http_body::Body trait 的对象也实现了 BodyExt
impl<T> BodyExt for T where T: Body + ?Sized,

impl<B> BodyDataStream<B> // A data stream created from a Body.
pub fn new(body: B) -> Self //  Create a new BodyDataStream
// BodyDataStream 实现了 Stream 和 StreamExt trait
impl<B> futures::stream::Stream for BodyDataStream<B> where B: Body,
  type Item = Result<<B as Body>::Data, <B as Body>::Error>

其它 HTTP 库也提供了实现 http_body::Body trait 和 http_body_util::BodyExt trait 的 body 类型,它们都可以作为异步 HTTP 请求或响应的 Body,如:

  • 这些类型在实现 http_body::Body 时,配置的 Data 关联类型为 bytes::Bytes, 它实现了 bytes::Buf trait.

  • Struct reqwest::Body;

      // https://docs.rs/reqwest/latest/reqwest/struct.Body.html#impl-Body-for-Body
      pub struct Body { /* private fields */ }
    
      impl http_body::Body for Body
        type Data = Bytes // bytes::Bytes
        type Error = Error
    
  • Struct axum::body::Body:

      // https://docs.rs/axum/latest/axum/body/struct.Body.html
      pub struct Body(/* private fields */); // The body type used in axum requests and responses.
    
      impl http_body::Body for Body
        type Data = Bytes
        type Error = Error
    
  • Struct hyper::body::Incoming:

      // https://docs.rs/hyper/latest/hyper/body/struct.Incoming.html
      pub struct Incoming { /* private fields */ }
    
      impl http_body::Body for Incoming
        type Data = Bytes
        type Error = Error
    
  • Struct hyper::Response:

      // https://docs.rs/hyper/latest/hyper/struct.Response.html
      pub struct Response<T> { /* private fields */ }
    
      impl<B> Body for Response<B> where B: Body, // B 一般为 IncomingBody 类型,它实现了 Body, Data 为 Bytes
        type Data = <B as Body>::Data
        type Error = <B as Body>::Error
    
      // https://docs.rs/hyper/latest/hyper/client/conn/http1/struct.SendRequest.html#method.send_request
      impl<B> SendRequest<B> where B: Body + 'static
      pub fn send_request(
          &mut self,
          req: Request<B>,
      ) -> impl Future<Output = Result<Response<IncomingBody>>>
    

注:hyper::body::Body 实际是 http_body::Body trait 的 use export。

示例:

#![deny(warnings)]
#![warn(rust_2018_idioms)]
use std::env;
use bytes::Bytes;
use http_body_util::{BodyExt, Empty};
use hyper::Request;
use tokio::io::{self, AsyncWriteExt as _};
use tokio::net::TcpStream;

#[path = "../benches/support/mod.rs"]
mod support;
use support::TokioIo;

// A simple type alias so as to DRY.
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;

#[tokio::main]
async fn main() -> Result<()> {
    pretty_env_logger::init();

    // Some simple CLI args requirements...
    let url = match env::args().nth(1) {
        Some(url) => url,
        None => {
            println!("Usage: client <url>");
            return Ok(());
        }
    };

    // HTTPS requires picking a TLS implementation, so give a better warning if the user tries to
    // request an 'https' URL.
    let url = url.parse::<hyper::Uri>().unwrap();
    if url.scheme_str() != Some("http") {
        println!("This example only works with 'http' URLs.");
        return Ok(());
    }

    fetch_url(url).await
}

async fn fetch_url(url: hyper::Uri) -> Result<()> {
    let host = url.host().expect("uri has no host");
    let port = url.port_u16().unwrap_or(80);
    let addr = format!("{}:{}", host, port);

    let stream = TcpStream::connect(addr).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 path = url.path();
    let req = Request::builder()
        .uri(path)
        .header(hyper::header::HOST, authority.as_str())
        .body(Empty::<Bytes>::new())?; // 使用 http_body_util::Empty 来设置空的 Request Body.

    // res 是 Struct hyper::Response 类型,实现了 hyper::body::Body trait 即 http_body::Body trait
    // 具体类型是 Struct hyper::body::Incoming
    let mut res = sender.send_request(req).await?;

    println!("Response: {}", res.status());
    println!("Headers: {:#?}\n", res.headers());

    // res 是 Struct hyper::body::Incoming 类型,实现了 http_body::Body 和 http_body_util::BodyExt
    // trait 这里调用 BodyExt 提供的 frame() 方法,
    while let Some(next) = res.frame().await {
        let frame = next?;
        if let Some(chunk) = frame.data_ref() { // 获取 frame 中数据,chunk 类型是 bytes::Bytes
            io::stdout().write_all(&chunk).await?;
        }
    }

    // 或者使用 http_body_util::BodyExt 提供的 collect() 方法,一次聚合所有 Body 的内容。

    // asynchronously aggregate the chunks of the body
    // let body = res.collect().await?.aggregate();
    // // try to parse as json with serde_json
    // let users = serde_json::from_reader(body.reader())?;

    Ok(users)

    println!("\n\nDone!");
    Ok(())
}
rust crate - 这篇文章属于一个选集。
§ 16: 本文

相关文章

reqwest
··3458 字
Rust Rust-Crate
reqwest 是在 hyper 基础上实现的高层 HTTP Client 库,支持异步和同步。
axum
··12636 字
Rust Rust-Crate
axum 是基于 hyper 实现的高性能异步 HTTP 1/2 Server 库。
clap
··5086 字
Rust Rust-Crate
diesel
··34358 字
Rust Rust-Crate
diesel 是高性能的 ORM 和 Query Builder,crates.io 使用它来操作数据库。