http/http_body crate 是公共的 http 和 body 定义,在 tokio 系列项目,如 hyper/axum/reqwest,中得到广泛应用,这些 crate 通过 import + pub use 的方式将 http/http_body 的类型导入和使用。
比如 reqwest::method 实际是 http::method , 但是也有一些是封装,例如 reqwest::Request/reqwest::Response 是 http::Request 和 http::Response 的封装。
*Ouest
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::builder() 函数返回的是 Request<()> 类型;
- Request<T> :设置 body 内容为 T 类型。T 没有限界,所以默认是 Sized;
- Request::new(body: T) 函数返回的是 Request<()> 类型;
Request 由 Parts + body 组成,Parts 是 Request 中除 body 外的信息(类似的还有 http::response::Parts 表示 Response 中除 body 外的内容)。
Request 还可以关联 Extensions,用来传递一些自定义内容。
- 类似于 Context,是根据值类型来保存和获取的,所以一般需要和自定义类型结合使用。
// 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,
pub fn new(body: T) -> Request<T> // 创建一个 HTTP 1.1 GET / 请求
let request = Request::new("hello world"); // 内容为 body
assert_eq!(*request.method(), Method::GET);
assert_eq!(*request.body(), "hello world");
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 用于设置 Request 的具体参数:的方法可以设置
- body<T>(self, body: T):消耗 Builder,使用传入的 body 内容返回一个 Request。
// 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))
}
1 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::builder() 返回 Response<()> 类型;
-
Response<T> :设置 body 内容为 T 类型的响应。T 没有限界,所以默认是 Sized。
- response::new(body: T) 返回 Response<T> 类型;
// 创建一个 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) -> Builder where 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) -> 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>>
// 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() 方法返回一个 Response<T> 对象
builder.body(())
}
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))
}
2 header #
http::header module 提供了三个类型:
- HeaderMap
- HTTP headers 集合
- HeaderName
- HTTP header field name
- HeaderValue
- HTTP header field value
HeaderName 提供了大小写不敏感的 header field name(内部会进行小写归一化),以加快比较和处理。
- 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);
// HeaerName 实现了 FromStr,姑可以使用字符串的 parse() 方法来创建 HeaderName
impl FromStr for HeaderName
http::header module 提供了标准的 HeaderName 常量定义:
pub const ACCEPT: HeaderName;
pub const RANGE: HeaderName;
// ...
HeaderValue 代表一个值,而 HasherMap 为 HeaderName 关联一系列 HeaderValue 值:
- Header Value 一般 ASCII 字符串,但是 HTTP spec 没有做强制要求,所以也可能是二进制值;
- HeaderValue 封装了上面的差别语义。
pub struct HeaderValue { /* private fields */ }
impl HeaderValue
pub const fn from_static(src: &'static str) -> HeaderValue
pub fn from_str(src: &str) -> Result<HeaderValue, InvalidHeaderValue>
pub fn from_name(name: HeaderName) -> HeaderValue
pub fn from_bytes(src: &[u8]) -> Result<HeaderValue, InvalidHeaderValue>
pub fn from_maybe_shared<T>(src: T) -> Result<HeaderValue, InvalidHeaderValue> where T: AsRef<[u8]> + 'static,
pub unsafe fn from_maybe_shared_unchecked<T>(src: T) -> HeaderValue where T: AsRef<[u8]> + 'static,
pub fn to_str(&self) -> Result<&str, ToStrError>
pub fn len(&self) -> usize
pub fn is_empty(&self) -> bool
pub fn as_bytes(&self) -> &[u8] ⓘ
pub fn set_sensitive(&mut self, val: bool)
pub fn is_sensitive(&self) -> bool
impl FromStr for HeaderValue // 可以使用 &str.parse() 来创建 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 解构,一个 heade field 可以有多个 header value,它的 APIs 接口和 HashMap 类似。
- T 代表 header value 值类型,默认为 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 中使用了 AsHeaderName trait,字符串均实现了它:
impl AsHeaderName for String
impl<'a> AsHeaderName for &'a str
impl<'a> AsHeaderName for &'a String
impl AsHeaderName for HeaderName
impl<'a> AsHeaderName for &'a HeaderName
HeaderMap 实现了 Extend/FromIterators/TryFrom trait,可以快速创建 HeaderMap:
- 但都要求使用 HeaderName 类型值;
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();
// parse() 将 &str 转换为 HeaderValue
headers.insert(HOST, "example.com".parse().unwrap());
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());
3 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");
4 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());
5 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"));
6 uri #
uri module 提供了 Uri/Parts/Port/Schema 等类型, Uri 并不等于 URL, Uri 可能只包含 Full URL 的部分内容。
Uri:
impl Uri
pub fn builder() -> Builder // 使用 Builder 来构造 Uri
pub fn from_parts(src: Parts) -> Result<Uri, InvalidUriParts>
pub fn from_maybe_shared<T>(src: T) -> Result<Self, InvalidUri> where T: AsRef<[u8]> + 'static,
pub fn from_static(src: &'static str) -> Self
pub fn into_parts(self) -> Parts
pub fn path_and_query(&self) -> Option<&PathAndQuery>
pub fn path(&self) -> &str
pub fn scheme(&self) -> Option<&Scheme>
pub fn scheme_str(&self) -> Option<&str>
pub fn authority(&self) -> Option<&Authority>
pub fn host(&self) -> Option<&str>
pub fn port(&self) -> Option<Port<&str>>
pub fn port_u16(&self) -> Option<u16>
pub fn query(&self) -> Option<&str>
示例:
// 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");
可以使用字符串或 Uri::Builder 来创建 Uri:
pub struct Builder { /* private fields */ }
impl Builder
pub fn new() -> Builder
pub fn scheme<T>(self, scheme: T) -> Self where Scheme: TryFrom<T>, <Scheme as TryFrom<T>>::Error: Into<Error>,
pub fn authority<T>(self, auth: T) -> Self where Authority: TryFrom<T>, <Authority as TryFrom<T>>::Error: Into<Error>,
pub fn path_and_query<T>(self, p_and_q: T) -> Self where PathAndQuery: TryFrom<T>, <PathAndQuery as TryFrom<T>>::Error: Into<Error>,
pub fn build(self) -> Result<Uri, Error>
// 示例
let uri = uri::Builder::new()
.scheme("https")
.authority("hyper.rs")
.path_and_query("/hello?foo=bar")
.build()
.unwrap();
7 http_body/http_body_util crate #
http crate
的 Request<T>
和 Response<T>
都是泛型类型,T 表示 HTTP Body 值类型。
http_body 提供了 Frame
和 SizeHint
类型,以及 Body trait
。
Frame<T>
: 代表任意类型的 HTTP Stream(Body),可以保存 data 或 trailers:
- T 是 data 的类型,在 Body trait 中使用该类型;
- trailers headers(类型为 HeaderMap)在 HTTP/2.0 中使用,表示 request/response exchange 的结束。
pub struct Frame<T> { /* private fields */ }
impl<T> Frame<T>
pub fn data(buf: T) -> Self
pub fn trailers(map: HeaderMap) -> Self
pub fn map_data<F, D>(self, f: F) -> Frame<D> where F: FnOnce(T) -> D
pub fn is_data(&self) -> bool
pub fn into_data(self) -> Result<T, Self>
pub fn data_ref(&self) -> Option<&T>
pub fn data_mut(&mut self) -> Option<&mut T>
pub fn is_trailers(&self) -> bool
pub fn into_trailers(self) -> Result<HeaderMap, Self>
pub fn trailers_ref(&self) -> Option<&HeaderMap>
pub fn trailers_mut(&mut self) -> Option<&mut HeaderMap>
Body trait
:代表 Request/Response 的 body Stream:
- 提供异步的 poll_frame() 方法,每次返回 body 的部分数据, 封装到上面的 Frame 类型中:
- Body 关联的 Data 类型需要实现 bytes::Buf trait,即包含读指针的缓冲区;
pub trait Body {
type Data: Buf;
type Error;
// Required method,返回的数据封装在 Frame 类型中
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 { ... }
}
Body 的实现类型:
- String 类型实现了
http_body::Body
。 - 当 B 是 http_body::Body 时,Request<B>/Response<B> 也实现了 http_body::Body。
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>>>
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 库也提供了实现 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 */ } // B 一般为 IncomingBody 类型,它实现了 Body, Data 为 Bytes impl<B> Body for Response<B> where B: Body, 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 的 pub use export。
http_body_util crate
提供了如下类型:
- http_body_util::BodyExt trait:为 Body trait 添加一系列方便使用的方法和适配器;
- http_body_util::Empty:总是为空的 Body 实现;
- http_body_util::Full:包含一个 chunk 的 Body 实现;
- http_body_util::BodyDataStream:从 Body Data 创建一个 Stream;
- http_body_util::BodyStream:从 Body 创建一个 Stream;
- http_body_util::StreamBody:从 Stream 创建 Body;
http_body_util::BodyExt trait
:
- 提供了便于使用的 frame() 方法,
可以在 while 循环中连续调用,返回实现 Future 的 Frame
,可以流式迭代。 - 提供了 into_data_stream() 方法,将 Body::Data 数据转换为
BodyDataStream
,它实现了futures::stream::Stream trait
,通过使用futures::stream::StreamExt的 next() 等方法,可以流式迭代; - 提供了
collect()
方法,一次收集所有 Body 数据,而 frame() 需要持续迭代调用。 - with_trailers() 为 Body 添加 trailers;
所有实现了 http_body::Body trait 的对象 均实现
BodyExt。
pub trait BodyExt: Body { // http_body::Body
// Provided methods
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 { ... }
}
impl<T> BodyExt for T where T: Body + ?Sized,
BodyDataStream
实现了 Stream 和 StreamExt trait, 每次迭代返回 Body::Data 内容:
pub struct BodyDataStream<B> { /* private fields */ }
impl<B> BodyDataStream<B> // A data stream created from a Body.
pub fn new(body: B) -> Self // Create a new BodyDataStream
// B 必须是 http_body::Body trait
impl<B> Stream for BodyDataStream<B> where B: Body,
type Item = Result<<B as Body>::Data, <B as Body>::Error>
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>>
fn size_hint(&self) -> (usize, Option<usize>)
Empty 是空的 Body 实现:
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.
Full 也实现了 Body:
use http::{Request, Response};
use tower::{ServiceBuilder, ServiceExt, Service};
use tower_http::trace::TraceLayer;
use std::convert::Infallible;
use http_body_util::Full;
use bytes::Bytes;
// Request 是 http::Request, Response 是 http::Resonse, Full<Bytes> 实现了 http_body::Body trait
async fn handle(request: Request<Full<Bytes>>) -> Result<Response<Full<Bytes>>, Infallible> {
Ok(Response::new(Full::default()))
}
tracing_subscriber::fmt::init();
let mut service = ServiceBuilder::new()
.layer(TraceLayer::new_for_http())
// 使用 ServiceBuilderExt 提供的 Layer 集成方法更方面
// .trace_for_http()
.service_fn(handle);
let request = Request::new(Full::from("foo"));
let response = service
.ready()
.await?
.call(request)
.await?;
示例:
use http::HeaderMap;
use http_body_util::{Full, BodyExt};
use bytes::Bytes;
async fn main() {
let (tx, rx) = tokio::sync::oneshot::channel::<HeaderMap>();
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 {
// ...
}
#![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(())
}