Rust 如何读取基于Tokio的超请求的整个正文?

Rust 如何读取基于Tokio的超请求的整个正文?,rust,hyper,rust-tokio,Rust,Hyper,Rust Tokio,我想使用Hyper的当前主分支编写一个服务器,它保存POST请求传递的消息,并将此消息发送到每个传入的GET请求 我有这个,主要是从Hyper-examples目录复制的: extern crate futures; extern crate hyper; extern crate pretty_env_logger; use futures::future::FutureResult; use hyper::{Get, Post, StatusCode}; use hyper::heade

我想使用Hyper的当前主分支编写一个服务器,它保存POST请求传递的消息,并将此消息发送到每个传入的GET请求

我有这个,主要是从Hyper-examples目录复制的:

extern crate futures;
extern crate hyper;
extern crate pretty_env_logger;

use futures::future::FutureResult;

use hyper::{Get, Post, StatusCode};
use hyper::header::{ContentLength};
use hyper::server::{Http, Service, Request, Response};
use futures::Stream;

struct Echo {
    data: Vec<u8>,
}

impl Echo {
    fn new() -> Self {
        Echo {
            data: "text".into(),
        }
    }
}

impl Service for Echo {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = FutureResult<Response, hyper::Error>;

    fn call(&self, req: Self::Request) -> Self::Future {
        let resp = match (req.method(), req.path()) {
            (&Get, "/") | (&Get, "/echo") => {
                Response::new()
                    .with_header(ContentLength(self.data.len() as u64))
                    .with_body(self.data.clone())
            },
            (&Post, "/") => {
                //self.data.clear(); // argh. &self is not mutable :(
                // even if it was mutable... how to put the entire body into it?
                //req.body().fold(...) ?
                let mut res = Response::new();
                if let Some(len) = req.headers().get::<ContentLength>() {
                    res.headers_mut().set(ContentLength(0));
                }
                res.with_body(req.body())
            },
            _ => {
                Response::new()
                    .with_status(StatusCode::NotFound)
            }
        };
        futures::future::ok(resp)
    }

}


fn main() {
    pretty_env_logger::init().unwrap();
    let addr = "127.0.0.1:12346".parse().unwrap();

    let server = Http::new().bind(&addr, || Ok(Echo::new())).unwrap();
    println!("Listening on http://{} with 1 thread.", server.local_addr().unwrap());
    server.run().unwrap();
}
extern板条箱期货;
外部板条箱;
外部板条箱漂亮的环境记录器;
使用futures::future::FutureResult;
使用hyper::{Get,Post,StatusCode};
使用hyper::header::{ContentLength};
使用hyper::server::{Http,服务,请求,响应};
使用流;
结构回声{
资料来源:Vec,
}
脉冲回波{
fn new()->Self{
回音{
数据:“text.into(),
}
}
}
Echo的impl服务{
类型请求=请求;
类型响应=响应;
类型错误=hyper::Error;
类型未来=未来结果;
fn调用(&self,req:self::Request)->self::Future{
让resp=match(req.method(),req.path()){
(&Get,“/”)|(&Get,“/echo”)=>{
响应::new()
.with_头(ContentLength(self.data.len()作为u64))
.with_body(self.data.clone())
},
(&Post,“/”)=>{
//self.data.clear();//argh.&self是不可变的:(
//即使它是可变的…如何把整个身体放进去?
//请求正文()折叠(…)?
让mut res=Response::new();
如果let Some(len)=req.headers().get::(){
res.headers_mut().set(ContentLength(0));
}
res.with_body(请求body())
},
_ => {
响应::new()
.具有_状态(状态代码::NotFound)
}
};
未来::未来::正常(resp)
}
}
fn main(){
pretty_env_logger::init().unwrap();
让addr=“127.0.0.1:12346”。parse().unwrap();
让server=Http::new().bind(&addr,| | Ok(Echo::new()).unwrap();
println!(“使用1个线程侦听http://{}”,server.local_addr().unwrap());
server.run().unwrap();
}

如何将
req.body()
(它似乎是
)转换为
Vec
?我假设我必须以某种方式返回一个
未来的
,它消耗
,并将其转换为单个
Vec
,可能是
折叠()
。但我不知道如何做。

我将简化问题,只返回总字节数,而不是回显整个流

期货0.3 Hyper 0.13+
trystreamText::try\u fold
看看你是否只想把所有的数据都变成一个大斑点

访问流允许更细粒度的控制:

use futures::TryStreamExt; // 0.3.7
use hyper::{server::Server, service, Body, Method, Request, Response}; // 0.13.9
use std::convert::Infallible;
use tokio; // 0.2.22

#[tokio::main]
async fn main() {
    let addr = "127.0.0.1:12346".parse().expect("Unable to parse address");

    let server = Server::bind(&addr).serve(service::make_service_fn(|_conn| async {
        Ok::<_, Infallible>(service::service_fn(echo))
    }));

    println!("Listening on http://{}.", server.local_addr());

    if let Err(e) = server.await {
        eprintln!("Error: {}", e);
    }
}

async fn echo(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
    let (parts, body) = req.into_parts();
    match (parts.method, parts.uri.path()) {
        (Method::POST, "/") => {
            let entire_body = body
                .try_fold(Vec::new(), |mut data, chunk| async move {
                    data.extend_from_slice(&chunk);
                    Ok(data)
                })
                .await;

            entire_body.map(|body| {
                let body = Body::from(format!("Read {} bytes", body.len()));
                Response::new(body)
            })
        }
        _ => {
            let body = Body::from("Can only POST to /");
            Ok(Response::new(body))
        }
    }
}
我们可以使用
Vec
作为累加器。
Body
实现返回一个
。这实现了
Deref
,因此我们可以使用它将每个块的数据附加到
Vec

extern crate futures; // 0.1.23
extern crate hyper;   // 0.11.27

use futures::{Future, Stream};
use hyper::{
    server::{Http, Request, Response, Service}, Post,
};

fn main() {
    let addr = "127.0.0.1:12346".parse().unwrap();

    let server = Http::new().bind(&addr, || Ok(Echo)).unwrap();
    println!(
        "Listening on http://{} with 1 thread.",
        server.local_addr().unwrap()
    );
    server.run().unwrap();
}

struct Echo;

impl Service for Echo {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = Box<futures::Future<Item = Response, Error = Self::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        match (req.method(), req.path()) {
            (&Post, "/") => {
                let f = req.body()
                    .fold(Vec::new(), |mut acc, chunk| {
                        acc.extend_from_slice(&*chunk);
                        futures::future::ok::<_, Self::Error>(acc)
                    })
                    .map(|body| Response::new().with_body(format!("Read {} bytes", body.len())));

                Box::new(f)
            }
            _ => panic!("Nope"),
        }
    }
}
警告 所有这些解决方案都允许恶意最终用户发布无限大的文件,这将导致计算机内存不足。根据预期用途,您可能希望对读取的字节数设置某种上限,可能在某个断点写入文件系统

另见:

Hyper 0.13为此提供了一种新的解决方案

使用hyper::body;
使用hyper::{Body,Response};
pub异步fn read\u response\u body(res:response)->Result{
let bytes=body::to_bytes(res.into_body()).wait?;
Ok(字符串::from_utf8(bytes.to_vec()).expect(“响应不是有效的utf-8”))
}

关于此主题的大多数答案都过时或过于复杂。解决方案非常简单:

/*
初学者警告!!!此使用语句
很重要,所以我们以后可以使用.data()方法!!!
*/
使用hyper::body::HttpBody;
让我的_vector:Vec=request.into_body().data().wait.unwrap().unwrap().to_Vec();
让my_string=string::from_utf8(my_向量).unwrap();

你也可以使用
body::to_bytes
。这两种方法都很简单!别忘了正确处理
展开

回答了你一半的问题,所以我重新编写了你的问题,将重点放在独特的方面,帮助避免否决票。感谢你第一次编辑@Shepmaster。之后,它看起来真的很完美。不过r、 我不喜欢你的第二次编辑。我看不出链接的问题如何回答我的问题。他们甚至没有实现trait服务。你总是能够从中回滚任何你不同意的编辑或执行进一步的编辑。好的,那么我将为第一个问题打开一个新问题。谢谢。听起来不错。在这种情况下,我还建议你这样做创建并使用已发布版本的Hyper。链接到我上面建议的问题并说明为什么它对您的案例无效也会有很大帮助!您能否解释一下为什么您有
futures::future:ok()
在fold方法中,尽管您从
键入Future=…
?@JayStrictor中删除了
futuresult
,但由于给定给
fold
的闭包本身需要返回一个Future:
F:FnMut(T,Self::Item)->Fut
。这允许操作本身花费时间。由于
从_片扩展_
是同步的,我们使用
future::ok
来“提升”结果。这与
类型future=futuresult
非常不同,后者用作处理程序的返回值(我出于懒惰而将其框起来).Stream::fold(…)
可以替换为
Stream::concat2()
也一样。
Chunk
本身就是
Extend
,因此
concat2
的结果将是一个包含整个身体的
Chunk
。@proc@M.Leonhard您可能希望对读取的字节数建立某种上限,可能在某个断点写入文件系统。-我的建议on不是要wr
use futures::{
    future::{self, Either},
    Future, Stream,
}; // 0.1.25

use hyper::{server::Server, service, Body, Method, Request, Response}; // 0.12.20

use tokio; // 0.1.14

fn main() {
    let addr = "127.0.0.1:12346".parse().expect("Unable to parse address");

    let server = Server::bind(&addr).serve(|| service::service_fn(echo));

    println!("Listening on http://{}.", server.local_addr());

    let server = server.map_err(|e| eprintln!("Error: {}", e));
    tokio::run(server);
}

fn echo(req: Request<Body>) -> impl Future<Item = Response<Body>, Error = hyper::Error> {
    let (parts, body) = req.into_parts();

    match (parts.method, parts.uri.path()) {
        (Method::POST, "/") => {
            let entire_body = body.concat2();
            let resp = entire_body.map(|body| {
                let body = Body::from(format!("Read {} bytes", body.len()));
                Response::new(body)
            });
            Either::A(resp)
        }
        _ => {
            let body = Body::from("Can only POST to /");
            let resp = future::ok(Response::new(body));
            Either::B(resp)
        }
    }
}
fn fold<F, T, Fut>(self, init: T, f: F) -> Fold<Self, F, Fut, T>
where
    F: FnMut(T, Self::Item) -> Fut,
    Fut: IntoFuture<Item = T>,
    Self::Error: From<Fut::Error>,
    Self: Sized,
extern crate futures; // 0.1.23
extern crate hyper;   // 0.11.27

use futures::{Future, Stream};
use hyper::{
    server::{Http, Request, Response, Service}, Post,
};

fn main() {
    let addr = "127.0.0.1:12346".parse().unwrap();

    let server = Http::new().bind(&addr, || Ok(Echo)).unwrap();
    println!(
        "Listening on http://{} with 1 thread.",
        server.local_addr().unwrap()
    );
    server.run().unwrap();
}

struct Echo;

impl Service for Echo {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = Box<futures::Future<Item = Response, Error = Self::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        match (req.method(), req.path()) {
            (&Post, "/") => {
                let f = req.body()
                    .fold(Vec::new(), |mut acc, chunk| {
                        acc.extend_from_slice(&*chunk);
                        futures::future::ok::<_, Self::Error>(acc)
                    })
                    .map(|body| Response::new().with_body(format!("Read {} bytes", body.len())));

                Box::new(f)
            }
            _ => panic!("Nope"),
        }
    }
}