Подтвердить что ты не робот

Как сделать запрос HTTP от Rust?

Как я могу сделать HTTP-запрос от Rust? Я не могу найти ничего в основной библиотеке.

Мне не нужно анализировать вывод, просто сделайте запрос и проверьте код ответа HTTP.

Бонусные баллы, если кто-то может показать мне, как URL-адрес кодирует параметры запроса в моем URL-адресе!

4b9b3361

Ответ 1

Обновление: Этот ответ относится к довольно древней истории. Чтобы ознакомиться с текущими рекомендациями, посмотрите ответ исаака Аггри.


Я работал над rust-http, который стал де-факто HTTP-библиотекой для Rust (Servo использует ее); это далеко не полный и очень плохо документированный в настоящее время. Вот пример того, как сделать запрос и сделать что-то с кодом состояния:

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

Запустите этот код с URL-адресом в качестве единственного аргумента командной строки, и он проверит код состояния! (Только HTTP; без HTTPS.)

Сравните с src/examples/client/client.rs пример, который немного больше.

rust-http отслеживает основную ветвь ржавчины. В настоящее время он будет работать в только что выпущенной версии Rust 0.8, но, скорее всего, скоро произойдут критические изменения. На самом деле ни одна версия rust-http не работает на Rust 0.8 - произошли критические изменения, которые могут не работайте в правилах конфиденциальности непосредственно перед выпуском, оставляя что-то, от чего зависит rust-http, в extra :: url, недоступном. С тех пор это было исправлено, но ржавчина-http несовместима с Rust 0.8.


Что касается кодировки строки запроса, то в настоящее время это должно быть сделано с помощью extra::url::Query (typedef для ~[(~str, ~str)]). Подходящие функции для конверсий:

Ответ 2

Самый простой способ сделать HTTP в Rust - это reqwest. Это оболочка для упрощения использования Hyper.

Hyper является популярной HTTP-библиотекой для Rust и использует две библиотеки: цикл событий Tokio для выполнения неблокирующих запросов и futures-rs для фьючерсов/обещаний. Пример Hyper -based приведен ниже и во многом вдохновлен примером из его документации.

// Rust 1.36, Hyper 0.12.35, tokio-core 0.1.17, futures 0.1.29

extern crate futures;
extern crate hyper;
extern crate tokio_core;

use futures::{Future};
use hyper::{Client, Uri};
use tokio_core::reactor::Core;

fn main() {
    // Core is the Tokio event loop used for making a non-blocking request
    let mut core = Core::new().unwrap();

    let client = Client::new();

    let url : Uri = "http://httpbin.org/response-headers?foo=bar".parse().unwrap();
    assert_eq!(url.query(), Some("foo=bar"));

    let request_result = core.run(client
        .get(url)
        .map(|res| {
            println!("Response: {}", res.status());
        })
        .map_err(|err| {
            println!("Error: {}", err);
       })
    );

}

В Cargo.toml:

[dependencies]
hyper = "0.12.35"
tokio-core = "0.1.17"
futures = "0.1.29"

Для потомков я оставил свой оригинальный ответ ниже, но см. выше обновление для Rust 1.19 (последняя стабильная версия) на момент написания статьи).

Я считаю, что вы ищете в стандартной библиотеке. Теперь в rust-http и Крис Морган ответ является стандартным способом в текущем Rust в обозримом будущем. Я не уверен, насколько далеко я могу вас взять (и надеюсь, что я вас не уведу в неправильном направлении!), но вы захотите что-то вроде:

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

Что касается кодирования, в модульных тестах есть несколько примеров в src/libstd/net_url.rs.

Ответ 3

Использование привязок скручивания. Вставьте это в свой Cargo.toml:

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

... и это в 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());    

}

Ответ 4

Чтобы прояснить вопрос об Исааке, вот пример создания запроса POST с параметрами запроса с использованием библиотеки reqwest.

Cargo.toml

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

[dependencies]
reqwest = "0.9.14"
tokio = "0.1.18"
futures = "0.1.21"

код

use futures::{Future, Stream};
use reqwest::r#async::{Client, Decoder};
use std::mem;

fn post_greeting() -> impl Future<Item=(), Error=()> {
    Client::new()
        .get("https://webhook.site/1dff66fd-07ff-4cb5-9a77-681efe863747")
        .header("Accepts", "application/json")
        .query(&[
            ("hello", "1"),
            ("world", "ABCD"),
        ])
        .send()
        .and_then(|mut res| {
            println!("{}", res.status());
            let body = mem::replace(res.body_mut(), Decoder::empty());
            body.concat2()
        })
        .map_err(|err| println!("request error: {}", err))
        .map(|body| {
            let v = body.to_vec();
            let s = String::from_utf8_lossy(&v);
            println!("response: {} ", s);
        })
}

fn main() {
    let f = post_greeting();
    tokio::run(f);
}

Перейдите на https://webhook.site, создайте ссылку на веб-крючок и измените код. Вы увидите запрос в режиме реального времени на сервере.

Основано в основном на примере Бастиана Грубера здесь https://github.com/gruberb/futures_playground