2017-07-05 121 views
1

我试图实现与超v0.11内置客户端重试,但我不能找到一种方法来重新用于不同的尝试的请求:实现与超HTTP客户端重试

#[macro_use] 
extern crate hyper; 
extern crate futures; 
extern crate tokio_core; 

use futures::Future; 

use hyper::{Client, Body, Uri, StatusCode}; 
use hyper::server::{Request, Response}; 
use hyper::client::HttpConnector; 
use hyper::Get; 

use tokio_core::reactor::Core; 

fn main() { 

    let mut core = Core::new().expect("Event Loop"); 
    let handle = core.handle(); 
    let client = Client::new(&handle.clone()); 

    // Request 
    let json = r#"{"user":"Peter"}"#; 
    let mut req: Request<Body> = Request::new(Post, "http://localhost:8080/create/user".parse().unwrap()); 
    req.headers_mut().set(ContentType::json()); 
    req.headers_mut().set(ContentLength(json.len() as u64)); 
    req.set_body(json); 

    dispatch_request(&client, req, 2); 
} 

fn clone_req(req: &Request) -> Request { 
    let mut new_req = Request::new(req.method().clone(), req.uri().clone()); 
    new_req.headers_mut().extend(req.headers().iter()); 
    new_req.set_body(req.body()); // <------- here the error occur! 
    new_req 
} 

fn dispatch_request(
    client: &Client<HttpConnector, Body>, 
    req: Request<Body>, 
    n_retry: u32, 
) -> Box<Future<Error = hyper::Error, Item = Response>> { 
    println!("Attemp {}", n_retry); 
    let max_retry = 3; 

    let client_clone = client.clone(); 

    let clone_req = clone_req(&req); 

    let resp = client.request(req).then(move |result| match result { 
     Ok(client_resp) => { 
      if client_resp.status() == hyper::StatusCode::Ok { 
       Box::new(futures::future::ok(client_resp)) 
      } else if n_retry < max_retry { 
       dispatch_request(&client_clone, clone_req, max_retry + 1) 
      } else { 
       Box::new(futures::future::ok(
        Response::new().with_status(StatusCode::ServiceUnavailable), 
       )) 
      } 
     } 
     Err(e) => { 
      println!("Connection error: {:?}", &e); 
      Box::new(futures::future::ok(
       Response::new().with_status(StatusCode::ServiceUnavailable), 
      )) 
     } 
    }); 
    Box::new(resp) 
} 

这是编译错误:

error[E0507]: cannot move out of borrowed content 
    --> src/main.rs:28:22 
    | 
28 |  new_req.set_body(req.body()); 
    |      ^^^ cannot move out of borrowed content 

的错误是明显的,但我不知道如何解决它。

+0

我不知道是否可以复制身体,因为身体是一个流。 – Stargateur

+0

为了用'body()'接受请求的正文,你必须拥有请求,但在'clone_req'中你只有一个引用。你有没有看过很多[现有的问题与相同的错误信息](https://stackoverflow.com/search?q=%5Brust%5D+cannot+move+out+of+borrowed+content)这可能会给你洞悉你在做什么错了? –

+0

@ E_net4是的,我花了很多时间寻找一些解决方法,看到试图在其他变量中写入正文(例如流)的示例,等等,但我无法修复它。 – cspinetta

回答

-1

为什么不在主循环中重试?请注意,您还需要在某处执行core.run

loop { 
    let req = Request::new(Get, "http://www.google.com".parse().unwrap()); 
    let resp = dispatch_request(&client, req,); 
    if let Ok(_) = resp.wait() { 
     break 
    } 
} 
+0

感谢您的回应!但是,您的建议不足以涵盖我需要的功能。我需要为**所有类型的请求**准备重试方案,并且请求也是从外部给出的,因为它是代理。我需要一种方法来传播传入的请求以传出新的请求(类似于传入,但与其他主机),问题是如何传播主体(理想情况下不使用'.concat()'来传播以正确的方式潜在地流出大块) – cspinetta