Как правильно извлечь тело ответа actix_web в строку? - PullRequest
0 голосов
/ 07 января 2019

Я пытаюсь использовать 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 ]

0 голосов
/ 07 января 2019

Дополняя ответ Себастьяна, вы также можете решить будущее MessageBody:

.and_then(|response| {
    response.body().map_err(|_| ()).and_then(|bytes| {
        println!("{:?}", bytes);
        Ok(())
    })
})
0 голосов
/ 08 января 2019
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. ClientResponse реализует HttpMessage, который имеет метод HttpMessage::body. Это возвращает будущее, которое разрешается в Bytes. Это можно преобразовать в String с помощью обычных методов Rust.

Смотри также:

0 голосов
/ 07 января 2019

Чтобы сохранить объект 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() позволяет мне извлечь тело. Когда это будет решено, mapmove, удостоверяющимся, что мы берем с собой response), затем возвращает кортеж (response, body)
  • Оттуда вы можете свободно использовать либо ответ, либо тело, как считаете нужным

Обратите внимание, что я заменил ваше имя хоста на localhost в целях тестирования, поскольку ipv4.canhasip.com в настоящее время не разрешается ни с чем снаружи.


Первоначальный ответ:

Вы действительно должны были предоставить больше контекста по этому вопросу. actix имеет более одного типа запроса.

Ваш начальный объект (response) - это ClientResponse. вызов body() для него возвращает структуру MessageBody, которая является началом кроличьей норы, в которую вы попали. Это NOT фактического тела, просто объект, реализующий черту Future и который после прохождения курса даст то, что вам нужно.

Вам нужно будет сделать это менее хакерским способом, но сейчас и чтобы убедить себя, что это источник проблемы, а не строка кода, попробуйте следующее:

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

Вызов wait() в будущем блокирует текущий поток, поэтому я говорю, что это временный, хакерский способ показать вам, в чем проблема. В зависимости от того, что у вас есть (если у вас есть объект, похожий на исполнителя, или вы можете вернуть будущее для выполнения), ваше реальное решение будет отличаться.

...