sve*_*aro 6 middleware rust actix-web
我想在 actix-web 1.0 的中间件中读出正文。我正在使用闭包式中间件,使用wrap_fn.
我的基本设置是这样的:
let mut server = HttpServer::new(move || {
ActixApp::new()
.wrap_fn(|req, srv| {
srv.call(req).map(|res| {
let req_ = res.request();
let body = req_.magical_body_read_function();
dbg!(body);
res
})
})
});
Run Code Online (Sandbox Code Playgroud)
我需要那个magical_body_read_function()可悲的是不存在的东西。
我通过阅读示例和使用将一些看起来可以工作的东西拼凑在一起take_payload(),但遗憾的是它没有工作:
let mut server = HttpServer::new(move || {
ActixApp::new()
.wrap_fn(|req, srv| {
srv.call(req).map(|res| {
let req_ = res.request();
req_.take_payload()
.fold(BytesMut::new(), move |mut body, chunk| {
body.extend_from_slice(&chunk);
Ok::<_, PayloadError>(body)
})
.and_then(|bytes| {
info!("request body: {:?}", bytes);
});
res
})
})
});
Run Code Online (Sandbox Code Playgroud)
给我
error[E0599]: no method named `fold` found for type `actix_http::payload::Payload<()>` in the current scope --> src/main.rs:209:26
| 209 | .fold(BytesMut::new(), move |mut body, chunk| {
| ^^^^
|
= note: the method `fold` exists but the following trait bounds were not satisfied:
`&mut actix_http::payload::Payload<()> : std::iter::Iterator`
Run Code Online (Sandbox Code Playgroud)
然后我尝试了一种使用完整中间件的方法:
pub struct Logging;
impl<S, B> Transform<S> for Logging
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = LoggingMiddleware<S>;
type Future = FutureResult<Self::Transform, Self::InitError>;
fn new_transform(&self, service: S) -> Self::Future {
ok(LoggingMiddleware { service })
}
}
pub struct LoggingMiddleware<S> {
service: S,
}
impl<S, B> Service for LoggingMiddleware<S>
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Box<dyn Future<Item = Self::Response, Error = Self::Error>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready()
}
fn call(&mut self, req: ServiceRequest) -> Self::Future {
Box::new(self.service.call(req).and_then(|res| {
let req_ = res.request();
req_.take_payload()
.fold(BytesMut::new(), move |mut body, chunk| {
body.extend_from_slice(&chunk);
Ok::<_, PayloadError>(body)
})
.and_then(|bytes| {
info!("request body: {:?}", bytes);
});
Ok(res)
}))
}
}
Run Code Online (Sandbox Code Playgroud)
遗憾的是,这也导致了非常相似的错误:
error[E0599]: no method named `fold` found for type `actix_http::payload::Payload<()>` in the current scope
--> src/main.rs:204:18
|
204 | .fold(BytesMut::new(), move |mut body, chunk| {
| ^^^^
|
= note: the method `fold` exists but the following trait bounds were not satisfied:
`&mut actix_http::payload::Payload<()> : futures::stream::Stream`
`&mut actix_http::payload::Payload<()> : std::iter::Iterator`
`actix_http::payload::Payload<()> : futures::stream::Stream`
Run Code Online (Sandbox Code Playgroud)
小智 5
在 svenstaro 的解决方案的基础上,您可以执行以下操作来在克隆剥离的字节后重建请求。
fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
let mut svc = self.service.clone();
Box::new(
req.take_payload()
.fold(BytesMut::new(), move |mut body, chunk| {
body.extend_from_slice(&chunk);
Ok::<_, PayloadError>(body)
})
.map_err(|e| e.into())
.and_then(move |bytes| {
println!("request body: {:?}", bytes);
let mut payload = actix_http::h1::Payload::empty();
payload.unread_data(bytes.into());
req.set_payload(payload.into());
svc.call(req).and_then(|res| Ok(res))
}),
)
}
Run Code Online (Sandbox Code Playgroud)
在 actix-web Gitter 频道的优秀人士的帮助下,我找到了这个解决方案,并为其制作了PR。
完整的解决方案是:
pub struct Logging;
impl<S: 'static, B> Transform<S> for Logging
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = LoggingMiddleware<S>;
type Future = FutureResult<Self::Transform, Self::InitError>;
fn new_transform(&self, service: S) -> Self::Future {
ok(LoggingMiddleware {
service: Rc::new(RefCell::new(service)),
})
}
}
pub struct LoggingMiddleware<S> {
// This is special: We need this to avoid lifetime issues.
service: Rc<RefCell<S>>,
}
impl<S, B> Service for LoggingMiddleware<S>
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>
+ 'static,
S::Future: 'static,
B: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Box<dyn Future<Item = Self::Response, Error = Self::Error>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready()
}
fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
let mut svc = self.service.clone();
Box::new(
req.take_payload()
.fold(BytesMut::new(), move |mut body, chunk| {
body.extend_from_slice(&chunk);
Ok::<_, PayloadError>(body)
})
.map_err(|e| e.into())
.and_then(move |bytes| {
println!("request body: {:?}", bytes);
svc.call(req).and_then(|res| Ok(res))
}),
)
}
}
Run Code Online (Sandbox Code Playgroud)