我正在使用rust
和actix-web
框架开发应用程序,然后将一些中间件实例插入到该应用程序中。
我计划中间件将修改响应的正文并在call()方法中返回响应,但是我找不到解决方案。我找不到能够从ServiceResponse
获取文本并对其进行修改的示例代码。
你们能帮我提供一些示例代码来获取响应的正文并进行修改吗?
以下是我使用的示例代码。我添加了一条评论,以告知我想要在{sample.rs“的SayHiMiddleware->call()
中做什么
// sample.rs
use actix_service::{Service, Transform};
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error};
use futures::future::{ok, FutureResult};
use futures::{Future, Poll};
// There are two steps in middleware processing.
// 1. Middleware initialization, middleware factory gets called with
// next service in chain as parameter.
// 2. Middleware's call method gets called with normal request.
pub struct SayHi;
// Middleware factory is `Transform` trait from actix-service crate
// `S` - type of the next service
// `B` - type of response's body
impl<S, B> Transform<S> for SayHi
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 = SayHiMiddleware<S>;
type Future = FutureResult<Self::Transform, Self::InitError>;
fn new_transform(&self, service: S) -> Self::Future {
ok(SayHiMiddleware { service })
}
}
pub struct SayHiMiddleware<S> {
service: S,
}
impl<S, B> Service for SayHiMiddleware<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 {
println!("Hi from start. You requested: {}", req.path());
Box::new(self.service.call(req).and_then(|res| {
// I want to get response body text and print the text.
// But I couldnt get the text from ServiceResponse instance..... help me guys T.T
// And is there way to combine with previous response body text and new text?????
// example (res->body->text is "aaaaa")) and I want to append new text to the string ( "aaaaa" + "bbbbb" )
println!("Hi from response");
Ok(res)
}))
}
}
// main.rs
use actix_web::{web, App, HttpServer};
use actix_service::Service;
use futures::future::Future;
#[allow(dead_code)]
mod redirect;
#[allow(dead_code)]
mod read_request_body;
#[allow(dead_code)]
mod read_response_body;
#[allow(dead_code)]
mod simple;
fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=debug");
env_logger::init();
HttpServer::new(|| {
App::new()
.wrap(redirect::CheckLogin)
.wrap(read_request_body::Logging)
.wrap(read_response_body::Logging)
.wrap(simple::SayHi)
.wrap_fn(|req, srv| {
println!("Hi from start. You requested: {}", req.path());
srv.call(req).map(|res| {
println!("Hi from response");
res
})
})
.service(web::resource("/login").to(|| {
"You are on /login. Go to src/redirect.rs to change this behavior."
}))
.service(
web::resource("/").to(|| {
"Hello, middleware! Check the console where the server is run."
}),
)
})
.bind("127.0.0.1:8080")?
.run()
}
谢谢...
答案 0 :(得分:0)
这就是我的工作。我认为可能有更好的方法,但示例很简单。
class HeaderContents extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
boxShadow: [BoxShadow(offset: Offset(0, 2), blurRadius: 5)]),
height: MediaQuery.of(context).size.height * 0.1,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
我的好友@stephaneyfx帮助我将其重构为更好的东西。
/// Extracts a response body of type T from `input`
/// Example:
///
/// let result: MyResponseBodyContract = TestContext::map_body(&mut resp).await;
pub async fn map_body<T>(input: &mut ServiceResponse<Body>) -> T
where T: DeserializeOwned
{
let mut body = input.take_body();
let mut bytes = BytesMut::new();
while let Some(item) = body.next().await {
bytes.extend_from_slice(&item.unwrap());
}
let result: T = serde_json::from_slice(&bytes)
.unwrap_or_else(|_| panic!("map_body failed during deserialization"));
return result;
}