J'essaie d'utiliser actix_web pour récupérer et afficher le contenu d'une page Web. La requête HTTP se termine avec succès et je peux afficher la page Web, mais je veux lire le corps dans une String
pour l'impression.
J'ai essayé let my_ip: String = response.body () .into ();
mais j'obtiens une erreur qui dit
[dependencies] actix-web = "0.7" actix = "0.7" futures = "0.1"
Voici ce que j'ai jusqu'à présent:
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(()) }) }); }
3 Réponses :
Afin de conserver l'objet response
que vous avez tout en extrayant le corps, nous allons profiter du fait que, contrairement à quelques autres frameworks, vous pouvez extraire le corps sans déstructurer l'objet entier. Le code est ci-dessous:
println!("{:?}", response.body().wait())
Dans l'ordre:
std :: io :: Error
pour plus de facilité d'utilisation. Comme tous les types d'erreur actix
implémentent Error
, il est également possible de conserver les types d'origine and_then ()
me permet d'extraire le corps. Lorsque cela est résolu, une map
(avec move
s'assurant que nous prenons response
avec nous) puis renvoie un tuple de ( réponse, corps)
Notez que j'ai remplacé votre nom d'hôte par localhost
à des fins de test, car ipv4.canhasip.com
ne résout actuellement rien de l'extérieur.
Réponse initiale:
Vous auriez vraiment dû fournir plus de contexte sur celui-ci. actix
a plusieurs types de requête.
Votre objet initial ( réponse
) est un ClientResponse
. appeler body ()
dessus renvoie une structure MessageBody
, qui est le début du terrier dans lequel vous êtes tombé. Ce n'est PAS le corps réel, simplement un objet implémentant le trait Future
et qui, une fois qu'il aura suivi son cours, donnera ce que vous recherchez.
Vous devrez le faire de manière moins hacky, mais pour l'instant et pour vous convaincre que c'est la source du problème, au lieu de votre ligne de code, essayez ceci:
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(|_| ()) });
Désolé pour le manque de détails. Je ne savais pas qu'il y avait plusieurs types de demandes. J'ai édité la question avec un exemple. Voyez si cela aide.
La réponse de @BonsaiOak est retardée, le travail est ... inhabituellement intéressant . Modifier la réponse pour en fournir un peu plus.
Pour compléter la réponse de Sébastien, vous pouvez également résoudre le futur de MessageBody
:
.and_then(|response| { response.body().map_err(|_| ()).and_then(|bytes| { println!("{:?}", bytes); Ok(()) }) })
Je ne voulais pas aller aussi loin car, en raison de la brièveté de l'exemple de l'OP, il n'est pas garanti qu'il ne retourne pas déjà quelque chose implémentant IntoFuture
de où il a obtenu cet objet, d'où la mise en garde :-)
J'ai édité ma question avec un exemple. Voyez si cela aide.
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 }); The result of send is a SendRequest. This is a future that resolves into a ClientResponse. ClientResponse implements HttpMessage, which has the method HttpMessage::body. This returns a future that resolves into a Bytes. This can be converted into a String through the usual Rust methods.See also: How do I read the entire body of a Tokio-based Hyper request? How do I convert a Vector of bytes (u8) to a string
Quelle est la signification de drop
dans map_err
?
On dirait que drop
est une fonction prélude transmise à map_err
qui supprime l'erreur. doc.rust-lang.org/std/ops/trait.Drop. html doc.rust-lang.org/std/prelude
@Shepmaster Vous avez raison, je suis depuis si longtemps pour comprendre que ma question laissait beaucoup à désirer. J'ai parcouru et clarifié les choses et je me suis assuré que le message d'erreur correspondait exactement à l'exemple.
Pas de soucis; c'est super facile de se retrouver pris dans un problème sur lequel nous travaillons depuis un moment et de perdre de vue la vue d'ensemble!