How to Extract Hyper response.body() into a String

I want to get the Response body string on error response:

fn send_request_async(req: Request<Body>) -> Box<dyn Future<Item = String, Error = Error> + Send> {
	let https = hyper_rustls::HttpsConnector::new(1);
	let client = Client::builder().build::<_, Body>(https);
	Box::new(
		client
			.request(req)
			.map_err(|e| ErrorKind::RequestError(format!("Cannot make request: {}", e)).into())
			.and_then(|resp| {
				if !resp.status().is_success() {
					Either::A(err(ErrorKind::RequestError(format!(
						"Wrong response code: {}, with data: {:?}",
						resp.status(),
						resp.body()     <<<< please look here!
					))
					.into()))
				} else {
					Either::B(
						resp.into_body()
							.map_err(|e| {
								ErrorKind::RequestError(format!("Cannot read response body: {}", e))
									.into()
							})
							.concat2()
							.and_then(|ch| ok(String::from_utf8_lossy(&ch.to_vec()).to_string())),
					)
				}
			}),
	)
}

pub fn send_request(req: Request<Body>) -> Result<String, Error> {
	let task = send_request_async(req);
	let mut rt =
		Runtime::new().context(ErrorKind::Internal("can't create Tokio runtime".to_owned()))?;
	Ok(rt.block_on(task)?)
}

But the resp.body() Debug just return Body instead of the real content.
Could somebody please give me a quick and simple fix on this? Thanks a lot.

BTW, I'm using hyper = "0.12", futures = "0.1.21", and tokio = "0.1.7":

use futures::future::{err, ok, Either};
use http::uri::{InvalidUri, Uri};
use hyper::header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE, USER_AGENT};
use hyper::rt::{Future, Stream};
use hyper::{Body, Client, Request};
use hyper_rustls;
use serde::{Deserialize, Serialize};
use serde_json;
use tokio::runtime::Runtime;
...

With above code I can only get

"Wrong response code: 500 Internal Server Error, with data: Body"

Please, anybody can help on this? how to get the real data body instead of "Body" here?

From the hyper documentation, Body is a stream of Chunks. So, what you need to do is wait until the whole stream is received and join all the chunks together. Practically, it looks like you probably want to map() the stream of Chunks into a stream of Bytes using Chunk::into_bytes(), then call concat2() to collect them into a single Bytes, wait on the resulting Future to get the actual Bytes, and then you have something that can be dereferenced to a &[u8] which you can output. There may be an easier way to do that, but I'm not that familiar with hyper and futures.

1 Like