代码之家  ›  专栏  ›  技术社区  ›  BonsaiOak

如何将actix_web响应的主体提取为字符串?

  •  1
  • BonsaiOak  · 技术社区  · 6 年前

    我正在尝试使用 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>`
    

    这就是我目前所拥有的:

    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(())
                })
        });
    }
    

    相关依赖项版本:

    [dependencies]
    actix-web = "0.7"
    actix = "0.7"
    futures = "0.1"
    
    3 回复  |  直到 6 年前
        1
  •  2
  •   Sébastien Renauld    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(|_| ())
    });
    

    整齐:

    • 里面的东西现在都用了 std::io::Error 便于使用。既然所有 actix 错误类型实现 Error ,也可以保留原始类型
    • and_then() 允许我取出尸体。解决后,a map move 确保我们 响应 然后返回 (response, body)
    • 从那里,你可以自由地使用反应或身体,如你所见。

    请注意,我用 localhost 用于测试目的 ipv4.canhasip.com 当前无法解析外部的任何内容。


    初始答案:

    你真的应该提供更多的上下文。 阿克克斯 有多个请求类型。

    你最初的目标( 响应 是一个 ClientResponse . 打电话 body() 返回一个 MessageBody struct,这是你掉进兔子洞的起点。这是 不是 实际的实体,仅仅是实现 Future 一旦它完成了它的进程,它就会产生你想要的东西。

    您需要以一种不那么老套的方式来完成这项工作,但现在,为了让自己相信这是问题的根源,而不是您的代码行,请尝试以下操作:

    println!("{:?}", response.body().wait())
    

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

        2
  •  1
  •   Caio    6 年前

    补充巴斯蒂安的回答,你也可以解决这个问题。 MessageBody 未来:

    .and_then(|response| {
        response.body().map_err(|_| ()).and_then(|bytes| {
            println!("{:?}", bytes);
            Ok(())
        })
    })
    
        3
  •  1
  •   Shepmaster Tim Diekmann    6 年前
    actix::run(|| {
        client::get("http://ipv4.canhasip.com/")
            .header("User-Agent", "Actix-web")
            .finish()
            .unwrap()
            .send()
            .map_err(drop)
            .and_then(|response| response.body().map_err(drop))
            .map(|body| body.to_vec())
            .map(|body| String::from_utf8(body).unwrap())
            .map(drop) // Do *something* with the string, presumably
    });
    

    结果 send 是一个 SendRequest . 这是一个未来 ClientResponse . 客户响应 器具 HttpMessage ,它有方法 HttpMessage::body . 这将返回一个未来,该未来将解析为 Bytes . 这可以转换成 String 通过通常的生锈方法。

    参见:

    推荐文章