How do I make an HTTP request from Rust?

前端 未结 7 856
长情又很酷
长情又很酷 2020-12-02 12:04

How can I make an HTTP request from Rust? I can\'t seem to find anything in the core library.

I don\'t need to parse the output, just make a request and check the HT

相关标签:
7条回答
  • 2020-12-02 12:26

    To elaborate on Isaac Aggrey's answer, here's an example of making a POST request with query parameters using the reqwest library.

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

    Go to https://webhook.site and create your webhook link and change the code to match. You'll see the request was received on server in realtime.

    This example was originally based on Bastian Gruber's example and has been updated for modern Rust syntax and newer crate versions.

    0 讨论(0)
  • 2020-12-02 12:33

    using hyper "0.13"

    also using hyper-tls for https support

    Cargo.toml

    hyper = "0.13"
    hyper-tls = "0.4.1"
    tokio = { version = "0.2", features = ["full"] }
    

    Code

    extern crate hyper;
    use hyper::Client;
    use hyper::body::HttpBody as _;
    use tokio::io::{stdout, AsyncWriteExt as _};
    use hyper_tls::HttpsConnector;
    
    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    
        // http only
        // let client = Client::new(); 
    
        // http or https connections
        let client = Client::builder().build::<_, hyper::Body>(HttpsConnector::new());
    
        let mut resp = client.get("https://catfact.ninja/fact".parse()?).await?;
    
        println!("Response: {}", resp.status());
    
        while let Some(chunk) = resp.body_mut().data().await {
            stdout().write_all(&chunk?).await?;
        }
    
        Ok(())
    }
    

    adapted from https://hyper.rs/guides/client/basic/

    0 讨论(0)
  • 2020-12-02 12:44

    Update: This answer refers to fairly ancient history. For the current best practices, please look at Isaac Aggrey's answer instead.


    I've been working on rust-http, which has become the de facto HTTP library for Rust (Servo uses it); it's far from complete and very poorly documented at present. Here's an example of making a request and doing something with the status code:

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

    Run this code with a URL as the sole command-line argument and it'll check the status code! (HTTP only; no HTTPS.)

    Compare with src/examples/client/client.rs for an example that does a little more.

    rust-http is tracking the master branch of rust. At present it'll work in the just-released Rust 0.8, but there are likely to be breaking changes soon. Actually, no version of rust-http works on Rust 0.8—there was a breaking change which can't be worked around in privacy rules just before the release, leaving something that rust-http depends on in extra::url inaccessible. This has since been fixed, but it leaves rust-http incompatible with Rust 0.8.


    As for the query string encoding matter, at present that should be done with extra::url::Query (a typedef for ~[(~str, ~str)]). Appropriate functions for conversions:

    • extra::url::query_to_str

    • extra::url::query_from_str (sorry, can't use this just at present as it's private. PR to make it public about to come. In the mean time, this link actually shouldn't work, it's only available because of https://github.com/mozilla/rust/issues/7476.)

    0 讨论(0)
  • 2020-12-02 12:44

    The easiest way to do HTTP in Rust is reqwest. It is a wrapper to make Hyper easier to use.

    Hyper is a popular HTTP library for Rust which utilizes the Tokio event loop to make non-blocking requests. This relies on the futures crate for futures. A Hyper-based example is below and is largely inspired by an example in its documentation.

    use hyper::{Client, Uri};
    
    #[tokio::main]
    async fn main() {
        let client = Client::new();
    
        let url: Uri = "http://httpbin.org/response-headers?foo=bar"
            .parse()
            .unwrap();
        assert_eq!(url.query(), Some("foo=bar"));
    
        match client.get(url).await {
            Ok(res) => println!("Response: {}", res.status()),
            Err(err) => println!("Error: {}", err),
        }
    }
    

    In Cargo.toml:

    [dependencies]
    tokio = { version = "0.2.21", features = ["macros"] }
    hyper = "0.13.5"
    

    Original answer (Rust 0.6)

    I believe what you're looking for is in the standard library. now in rust-http and Chris Morgan's answer is the standard way in current Rust for the foreseeable future. I'm not sure how far I can take you (and hope I'm not taking you the wrong direction!), but you'll want something like:

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

    As for encoding, there are some examples in the unit tests in src/libstd/net_url.rs.

    0 讨论(0)
  • 2020-12-02 12:45

    I prefer Crates with low dependency count, so I would recommend these:

    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(())
    }
    
    0 讨论(0)
  • 2020-12-02 12:50

    Using curl bindings. Stick this in your Cargo.toml:

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

    ...and this in the 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());    
    
    }
    
    0 讨论(0)
提交回复
热议问题