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::Request 和 http::Response 的封装。
1 request #
http::request module 包含三个类型:
- struct Request
- struct Parts
- struct Builder
http::request::Request%3CT%3E 是泛型类型,T 对应 body 的数据类型:
- Request<()>:未设置 body 的请求,具有创建 Builder 的一系列函数,后续可以使用 Builder 的body()方法来设置 body 并返回对应的 Request<T> 类型对象;
- 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 包含:
-
Response struct
-
Parts struct
-
Builder struct
http::response::Response%3CT%3E 是泛型类型,T 对应 body 的数据类型:
-
Response<()>:未设置 body 的请求,具有创建 Builder 的一系列函数,后续可以使用 Builder 的body() 方法来设置 body 并返回对应的 Response<T> 类型对象;
-
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,
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
:
- 提供了便于使用的 frame() 方法,
可以在 while 循环中连续调用,返回实现 Future 的 Frame
,可以流式迭代。 - 提供了 into_data_stream() 方法,将 Body::Data 数据转换为
BodyDataStream
,它实现了 futures::stream::Stream trait,通过使用 futures::stream::StreamExt 的 next() 等方法,可以流式迭代; - 提供了 collect() 方法,可以一次收集所有 Body 数据,而 frame() 需要持续迭代调用。
- 所有实现了 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(())
}