将 actix_web 响应正文提取到字符串中的正确方法是什么?

Bon*_*Oak 5 actor rust rust-actix

我正在尝试使用actix_web来获取并显示网页的内容。HTTP 请求成功完成,我可以查看网页,但我想将正文读入String打印。

我尝试过let my_ip: String = response.body().into();,但收到一条错误消息

error[E0277]: the trait bound `std::string::String: std::convert::From<actix_web::httpmessage::MessageBody<actix_web::client::response::ClientResponse>>` is not satisfied
  --> src/main.rs:16:53
   |
16 |                 let my_ip: String = response.body().into();
   |                                                     ^^^^ the trait `std::convert::From<actix_web::httpmessage::MessageBody<actix_web::client::response::ClientResponse>>` is not implemented for `std::string::String`
   |
   = help: the following implementations were found:
             <std::string::String as std::convert::From<&'a str>>
             <std::string::String as std::convert::From<std::borrow::Cow<'a, str>>>
             <std::string::String as std::convert::From<std::boxed::Box<str>>>
             <std::string::String as std::convert::From<trust_dns_proto::error::ProtoError>>
   = note: required because of the requirements on the impl of `std::convert::Into<std::string::String>` for `actix_web::httpmessage::MessageBody<actix_web::client::response::ClientResponse>`
Run Code Online (Sandbox Code Playgroud)

这是我到目前为止所拥有的:

use actix;
use actix_web::{client, HttpMessage};
use futures::future::Future;

fn main() {
    actix::run(|| {
        client::get("http://ipv4.canhasip.com/")
            .header("User-Agent", "Actix-web")
            .finish()
            .unwrap()
            .send()
            .map_err(|_| ())
            .and_then(|response| {
                println!("Response: {:?}", response);
                // error occurs here
                let my_ip: String = response.body().into();
                Ok(())
            })
    });
}
Run Code Online (Sandbox Code Playgroud)

相关依赖版本:

[dependencies]
actix-web = "0.7"
actix = "0.7"
futures = "0.1"
Run Code Online (Sandbox Code Playgroud)

Séb*_*uld 6

为了保留response您拥有的对象,同时提取主体,我们将利用这样一个事实:与其他一些框架不同,您可以提取主体而无需解构整个对象。代码如下:

actix::run(|| {

    client::get("http://localhost/")
        .header("User-Agent", "Actix-web")
        .finish()
        .unwrap()
        .send()
        .map_err(|e| {
          Error::new(ErrorKind::AddrInUse, "Request error", e)
        })
        .and_then(|response| {
          println!("Got response");
          response.body().map(move |body_out| {
            (response, body_out)
          }).map_err(|e| Error::new(ErrorKind::InvalidData, "Payload error", e))
        }).and_then(|(response, body)| {
          println!("Response: {:?}, Body: {:?}", response, body);
          Ok(())
      }).map_err(|_| ())
});
Run Code Online (Sandbox Code Playgroud)

为了:

  • 现在,其中的所有内容都std::io::Error易于使用。由于所有actix错误类型都实现了Error,因此也可以保留原始类型
  • and_then()允许我提取尸体。当这个问题解决后, a mapmove确保我们随身携带response)然后返回一个元组(response, body)
  • 从那里,您可以根据需要自由使用响应或正文

请注意,localhost出于测试目的,我将您的主机名替换为,因为ipv4.canhasip.com目前无法解析外部的任何内容。


初步回答:

您确实应该提供更多有关此问题的背景信息。actix有不止一种请求类型。

您的初始对象 ( response) 是 a ClientResponse。调用body()它会返回一个MessageBody结构,这是您掉入的兔子洞的开始。这不是真正的身体,只是一个实现该Future特征的对象,一旦它运行完毕,它就会产生你想要的东西。

您需要以一种不那么麻烦的方式来执行此操作,但现在要说服自己这是问题的根源,而不是您的代码行,请尝试以下操作:

println!("{:?}", response.body().wait())
Run Code Online (Sandbox Code Playgroud)

调用wait()future 会阻塞当前线程,这就是为什么我说这是一种临时的、hacky 的方式来告诉你问题出在哪里。根据您可以使用的内容(如果您在某处有类似执行器的对象,或者能够返回执行的 future),您的实际解决方案将会有所不同。