Can't make a HTTP request in Hyper


#1

I have tried to make a request with rust and hyper but no error the code is ran but nothing appear in the console except my debug. If you can help me.
let client = Client::new();

let uri = "http://google.fr".parse().unwrap();
println!("Debug: {}", "1");
client
    .get(uri)
    .and_then(|res| {
        println!("Response: {}", res.status());
        res
            .into_body()
            // Body is a stream, so as each chunk arrives...
            .for_each(|chunk| {
                io::stdout()
                    .write_all(&chunk)
                    .map_err(|e| {
                        panic!("example expects stdout is open, error={}", e)
                    })
            })
    })
    .map_err(|err| {
        println!("Error: {}", err);
    });
    println!("Debug: {}", "2");

Tank’s for your help ccgauche.


#2

If I read the documentation, client.get(uri) will create a future. A future is like a description on how a task should be executed. A future must be spawn in an executor to work. The executer reads the “description” inside the future and executes it.

In the hyper-documentation, the rt::spawn(fut); does this. For more information, take a look at the “future” crate documentation.


#3

Tank’s but now I have an error
Debug: 1
thread ‘main’ panicked at ‘called Result::unwrap() on an Err value: SpawnError {
is_shutdown: true }’, libcore/result.rs:945:5
note: Run with RUST_BACKTRACE=1 for a backtrace.
If you understand that.


#4

Your error message is a bit thin. You can add the RUST_BACKTRACE=1 environment variable to see the full backtrace and to see which unwrap fails. But to do a first guess: spawn is async and returns immediate before the request is actually finished. So you have to make sure the main function stays alive until the future resolves (at least if you want the request to be finished).


#5

I want to wait until the operation is finish
let g = rt::spawn(rf); g.wait(); //Or something like that


#6

Is is some time ago since I used Future's (and hyper), but if I read the documenten [1], the run function seems to be more appropiate then the spawn function.

I think the documentation is much more clear then I can explain it.

[1] https://docs.rs/hyper/0.12.11/hyper/rt/index.html


#7

@mredlek is correct - you can only spawn a future from inside the context of an already running runtime. So, if you wanted to start a new future from within one of the and_then calls, spawn would work fine. For your initial future, however, you have to call run - this bootstraps the runtime and immediately spawns your future onto it.

The Tokio docs for the runtime module are probably the best place to look for info on this - Hyper just wraps around it.


#8

If you want to simply make a request and wait, then the reqwest crate may be better for you. It always waits itself, and it doesn’t use futures, so you don’t have to mess with runtimes, exectuors, combinators and all the other pains of futures.


#9
use hyper::Client;
use std::io::{self, Write};
use hyper::rt::{self, Future, Stream};


fn main() {
    rt::run(get());

}

fn get() -> impl Future<Item=(), Error=()> {
    let client = Client::new();
    let uri = "http://google.fr".parse().unwrap();
    client
        .get(uri)
        .and_then(|res| {
            res.into_body().for_each(|chunk| {
                io::stdout().write_all(&chunk)
                    .map_err(|e| panic!("stdout error: {}", e))
            })
        })
        .map_err(|err| {
            eprintln!("Error {}", err);
        })
}

This worked for me
notice that I am returning object with future trait into rt::run(). That println! will return () instead.


#10

If you are not passing that into rt::run I dont think it will work.