91 votes

Comment faire une requête HTTP à partir de Rust ?

Comment puis-je faire une requête HTTP à partir de Rust ? Je n'arrive pas à trouver quoi que ce soit dans la bibliothèque de base.

Je n'ai pas besoin d'analyser la sortie, il suffit de faire une demande et de vérifier le code de réponse HTTP.

Des points bonus si quelqu'un peut me montrer comment coder les paramètres de requête sur mon URL !

96voto

Isaac Aggrey Points 195

La façon la plus simple d'effectuer des requêtes HTTP en Rust est d'utiliser la fonction reqwest caisse :

use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let resp = reqwest::blocking::get("https://httpbin.org/ip")?.text()?;
    println!("{:#?}", resp);
    Ok(())
}

En Cargo.toml :

[dependencies]
reqwest = { version = "0.11", features = ["blocking"] }

Async

Reqwest soutient également la réalisation asynchrone Les requêtes HTTP utilisant Tokio :

use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let resp = reqwest::get("https://httpbin.org/ip")
        .await?
        .text()
        .await?;
    println!("{:#?}", resp);
    Ok(())
}

En Cargo.toml :

[dependencies]
reqwest = "0.11"
tokio = { version = "1", features = ["full"] }

Hyper

Reqwest est une enveloppe facile à utiliser autour de Hyper qui est une bibliothèque HTTP populaire pour Rust. Vous pouvez l'utiliser directement si vous avez besoin de plus de contrôle sur la gestion des connexions. A Hyper L'exemple ci-dessous s'inspire largement de l'exemple de l'Union européenne. un exemple dans sa documentation :

use hyper::{body::HttpBody as _, Client, Uri};
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let client = Client::new();

    let res = client
        .get(Uri::from_static("http://httpbin.org/ip"))
        .await?;

    println!("status: {}", res.status());

    let buf = hyper::body::to_bytes(res).await?;

    println!("body: {:?}", buf);
}

En Cargo.toml :

[dependencies]
hyper = { version = "0.14", features = ["full"] }
tokio = { version = "1", features = ["full"] }

Réponse originale (Rust 0.6)

Je crois que ce que vous cherchez se trouve dans le bibliothèque standard . maintenant dans rust-http et la réponse de Chris Morgan est la méthode standard dans Rust actuel pour un avenir prévisible. Je ne sais pas jusqu'où je peux vous emmener (et j'espère que je ne vous emmène pas dans la mauvaise direction !), mais vous voudrez quelque chose comme :

// Rust 0.6 -- old code
extern mod std;

use std::net_ip;
use std::uv;

fn main() {
    let iotask = uv::global_loop::get();
    let result = net_ip::get_addr("www.duckduckgo.com", &iotask);

    io::println(fmt!("%?", result));
}

Quant à l'encodage, il y a quelques exemples dans les tests unitaires dans src/libstd/net_url.rs.

32voto

Chris Morgan Points 22285

Mise à jour : Cette réponse fait référence à une histoire assez ancienne. Pour les meilleures pratiques actuelles, veuillez consulter La réponse d'Isaac Aggrey à la place.


J'ai travaillé sur rust-http qui est devenu le de facto Bibliothèque HTTP pour Rust (Servo l'utilise) ; elle est loin d'être complète et très mal documentée pour le moment. Voici un exemple de requête et de traitement du code d'état :

extern mod http;
use http::client::RequestWriter;
use http::method::Get;
use http::status;
use std::os;

fn main() {
    let request = RequestWriter::new(Get, FromStr::from_str(os::args()[1]).unwrap());
    let response = match request.read_response() {
        Ok(response) => response,
        Err(_request) => unreachable!(), // Uncaught condition will have failed first
    };
    if response.status == status::Ok {
        println!("Oh goodie, I got me a 200 OK response!");
    } else {
        println!("That URL ain't returning 200 OK, it returned {} instead", response.status);
    }
}

Exécutez ce code avec une URL comme seul argument de ligne de commande et il vérifiera le code d'état ! (HTTP uniquement ; pas de HTTPS.)

Comparer avec src/examples/client/client.rs pour un exemple qui en fait un peu plus.

rust-http suit la branche master de rust. Pour l'instant, il fonctionne dans la version 0.8 de Rust qui vient d'être publiée, mais il est probable que des modifications importantes soient apportées prochainement. En fait, aucune version de rust-http ne fonctionne sur Rust 0.8 - il y a eu un changement de rupture qui ne peut pas être contourné dans les règles de confidentialité juste avant la sortie, laissant quelque chose dont rust-http dépend dans extra::url inaccessible. Cela a depuis été corrigé, mais cela laisse rust-http incompatible avec Rust 0.8.


Pour ce qui est de l'encodage de la chaîne de requête, il doit actuellement être effectué à l'aide de la fonction extra::url::Query (un typedef pour ~[(~str, ~str)] ). Fonctions appropriées pour les conversions :

22voto

dvdplm Points 121

Utilisation des liaisons curl. Mettez ça dans votre Cargo.toml :

[dependencies.curl]
git = "https://github.com/carllerche/curl-rust"

...et ceci dans le src/main.rs :

extern crate curl;

use curl::http;

fn main(){
  let resp = http::handle()
    .post("http://localhost:3000/login", "username=dude&password=sikrit")
    .exec().unwrap();

  println!("code={}; headers={}; body={}",
    resp.get_code(), resp.get_headers(), resp.get_body());    

}

6voto

Steven Penny Points 18523

Je préfère les caisses avec un faible nombre de dépendances, donc je recommande celles-ci :

MinReq (0 deps)

use minreq;

fn main() -> Result<(), minreq::Error> {
   let o = minreq::get("https://speedtest.lax.hivelocity.net").send()?;
   let s = o.as_str()?;
   print!("{}", s);
   Ok(())
}

HTTP_Req (35 deps)

use {http_req::error, http_req::request, std::io, std::io::Write};

fn main() -> Result<(), error::Error> {
   let mut a = Vec::new();
   request::get("https://speedtest.lax.hivelocity.net", &mut a)?;
   io::stdout().write(&a)?;
   Ok(())
}

4voto

Patrik Stas Points 539

Pour approfondir La réponse d'Isaac Aggrey Voici un exemple d'une requête POST avec des paramètres d'interrogation à l'aide de l'outil de gestion des données. reqwest bibliothèque.

Cargo.toml

[package]
name = "play_async"
version = "0.1.0"
edition = "2018"

[dependencies]
reqwest = "0.10.4"
tokio = { version = "0.2.21", features = ["macros"] }

Code

use reqwest::Client;

type Error = Box<dyn std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;

async fn post_greeting() -> Result<()> {
    let client = Client::new();
    let req = client
        // or use .post, etc.
        .get("https://webhook.site/1dff66fd-07ff-4cb5-9a77-681efe863747")
        .header("Accepts", "application/json")
        .query(&[("hello", "1"), ("world", "ABCD")]);

    let res = req.send().await?;
    println!("{}", res.status());

    let body = res.bytes().await?;

    let v = body.to_vec();
    let s = String::from_utf8_lossy(&v);
    println!("response: {} ", s);

    Ok(())
}

#[tokio::main]
async fn main() -> Result<()> {
    post_greeting().await?;

    Ok(())
}

Aller à https://webhook.site et créer votre lien webhook et changer le code pour correspondre. Vous verrez que la requête a été reçue sur le serveur en temps réel.

Cet exemple était à l'origine basé sur L'exemple de Bastian Gruber et a été mis à jour pour la syntaxe moderne de Rust et les nouvelles versions de crate.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X