Как я могу реализовать пользовательский типизированный заголовок для использования с Hyper?
Я бы предпочел воспользоваться безопасностью типа Hyper's hyper::header::Headers#get
метод вместо использования get_raw
с &str
,
Каков наилучший способ сделать это?
2 ответа
Решение
Копаться в hyper::header::Headers
Исходный код, я обнаружил, что есть аккуратный макрос для генерации кода: header!
, Вам понадобится заклинание, чтобы сделать его полезным:
#[macro_use]
extern crate hyper;
use hyper::{Body, Method, Request, Response};
use std::fmt::{self, Display};
use std::str::FromStr;
use std::num::ParseIntError;
// For a header that looks like this:
// x-arbitrary-header-with-an-integer: 8
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ArbitraryNumber(i8);
impl Display for ArbitraryNumber {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Arbitrary Protocol v{}", self.0)
}
}
impl FromStr for ArbitraryNumber {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.parse::<i8>().map(|int| ArbitraryNumber(int))
}
}
//impl Header for ArbitraryNumberHeader
header! { (ArbitraryNumberHeader, "x-arbitrary-header-with-an-integer") => [ArbitraryNumber] }
Как только вы получили Response
названный res
в области, вы можете получить доступ к этому заголовку следующим образом:
let arbitrary_header: AribitraryNumber = res.headers().get::<ArbitraryNumberHeader>().unwrap();
Я думаю, за это время все изменилось. я не смог найтиheader!
макрос вhyper
. Это мое решение для реализации пользовательского заголовка (я использую axum, который реэкспортируется из Hyper, он должен работать так же без axum, только с другим импортом):
use axum::headers::Error;
use http::{HeaderName, HeaderValue};
#[derive(Eq, PartialEq, Clone, Hash)]
pub struct XXsrfToken(pub String);
pub static X_XSRF_TOKEN: HeaderName = HeaderName::from_static("x-xsrf-token");
impl axum::headers::Header for XXsrfToken {
fn name() -> &'static HeaderName {
&X_XSRF_TOKEN
}
fn decode<'i, I>(values: &mut I) -> Result<Self, Error>
where
Self: Sized,
I: Iterator<Item = &'i HeaderValue>,
{
values
.next()
.and_then(|v| v.to_str().ok())
.map(|it| XXsrfToken(it.to_string()))
.ok_or_else(Error::invalid)
}
fn encode<E: Extend<HeaderValue>>(&self, values: &mut E) {
let bytes = self.0.as_str().as_bytes();
let val = HeaderValue::from_bytes(bytes).expect("XXsrfToken is a valid HeaderValue");
values.extend(::std::iter::once(val));
}
}