如何在 Rust 中使用 hyper、tokio 和 futures 为 HTTP 请求设置超时?

How to set timeout for HTTP request with hyper, tokio and futures in Rust?

如何使用异步 Hyper (>= 0.11) 为 HTTP 请求设置超时?

这里是没有超时的代码示例:

extern crate hyper;
extern crate tokio_core;
extern crate futures;

use futures::Future;
use hyper::Client;
use tokio_core::reactor::Core;

fn main() {
    let mut core = Core::new().unwrap();
    let client = Client::new(&core.handle());

    let uri = "http://whosebug.com".parse().unwrap();
    let work = client.get(uri).map(|res| {
        res.status()
    });

    match core.run(work) {
        Ok(status) => println!("Status: {}", status),
        Err(e) => println!("Error: {:?}", e)
    }
}

根据 seanmonstar 提供给 Hyper Guide / General Timeout:

的 link,用工作代码示例回答我自己的问题
extern crate hyper;
extern crate tokio_core;
extern crate futures;

use futures::Future;
use futures::future::Either;
use hyper::Client;
use tokio_core::reactor::Core;
use std::time::Duration;
use std::io;

fn main() {
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let client = Client::new(&handle);

    let uri: hyper::Uri = "http://whosebug.com".parse().unwrap();
    let request = client.get(uri.clone()).map(|res| res.status());

    let timeout = tokio_core::reactor::Timeout::new(Duration::from_millis(170), &handle).unwrap();

    let work = request.select2(timeout).then(|res| match res {
        Ok(Either::A((got, _timeout))) => Ok(got),
        Ok(Either::B((_timeout_error, _get))) => {
            Err(hyper::Error::Io(io::Error::new(
                io::ErrorKind::TimedOut,
                "Client timed out while connecting",
            )))
        }
        Err(Either::A((get_error, _timeout))) => Err(get_error),
        Err(Either::B((timeout_error, _get))) => Err(From::from(timeout_error)),
    });

    match core.run(work) {
        Ok(status) => println!("OK: {:?}", status),
        Err(e) => println!("Error: {:?}", e)
    }
}

仅供参考,使用 Tokyo >= 1.0,这变得容易多了,因为他们现在有一个专用的 timeout 包装器,可以应用于未来(例如请求)并包装原始未来在 Result 中键入,其 Ok 是原始未来类型,其 Err 是超时错误。

因此问题中的代码现在可以按如下方式处理超时:

extern crate tokio; // 1.7.1, full features

use hyper::Client;
use std::time::Duration;

#[tokio::main]
async fn main() {
    let client = Client::new();


    let uri = "http://whosebug.com".parse().unwrap();
    let work = client.get(uri);

    match tokio::time::timeout(Duration::from_millis(10), work).await {
        Ok(result) => match result {
            Ok(response) => println!("Status: {}", response.status()),
            Err(e) => println!("Network error: {:?}", e),
        },
        Err(_) => println!("Timeout: no response in 10 milliseconds."),
    };
}

(当然,这段代码总是会给你一个超时。要看到预期的网络 301 响应,请尝试转到 200 毫秒。)