如何从Rust发出HTTP请求?

t1qtbnec  于 2022-11-12  发布在  其他
关注(0)|答案(9)|浏览(541)

我如何从Rust发出HTTP请求?我似乎在核心库中找不到任何东西。
我不需要解析输出,只需要发出请求并检查HTTP响应代码。
如果有人能告诉我如何对我的URL上的查询参数进行URL编码,那就更好了!

s4n0splo

s4n0splo1#

在Rust中发出HTTP请求最简单的方法是使用reqwest crate:

use std::error::Error;

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

Cargo.toml中:

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

异步

Reqwest还支持使用Tokio发出 * 异步 * HTTP请求:

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

Cargo.toml中:

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

超级
Reqwest是Hyper的一个简单易用的 Package 器,Hyper是Rust的一个流行的HTTP库。如果你需要更多的控制来管理连接,你可以直接使用它。下面是一个基于Hyper的例子,它很大程度上受到了an example in its 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);
}

Cargo.toml中:

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

原始答案(生 rust 0.6)

我相信你正在寻找的是在standard library中。现在在rust-http中,Chris Morgan的答案是在可预见的未来当前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的单元测试中有一些示例。

dsf9zpds

dsf9zpds2#

更新:这个答案涉及到相当古老的历史。对于当前的最佳实践,请改为查看Isaac Aggrey's answer

我一直在研究rust-http,它已经成为Rust的 * 事实上的 * HTTP库(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相比,src/examples/client/client.rs的功能更强。
rust-http正在跟踪rust的主分支。目前它可以在刚刚发布的Rust 0.8中工作,但可能很快就会有突破性的变化。* 实际上,没有一个版本的rust-http可以在Rust 0.8上工作-在发布前有一个突破性的变化,这在隐私规则中无法解决,使得rust-http依赖于extra::url的某些内容无法访问。这个问题已经得到修复,但它使rust-http与Rust 0.8不兼容。*
至于查询字符串的编码问题,目前应该用extra::url::Query来完成(typedef为~[(~str, ~str)]).适当的函数进行转换:

yptwkmov

yptwkmov3#

使用卷边装订。把这个贴在你的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());    

}
ojsjcaue

ojsjcaue4#

我更喜欢低依赖计数的板条箱,所以我会推荐这些:

MinReq(0个深度)

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个深度)

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

6yt4nkrj5#

为了详细说明Isaac Aggrey's answer,下面是一个使用reqwest库生成带有查询参数的POST请求的示例。
Cargo.toml

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

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

编码

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

进入https://webhook.site,创建你的webhook链接,修改代码,你会看到服务器实时收到请求。
此示例最初基于Bastian Gruber's example,并已针对现代Rust语法和更新的crate版本进行了更新。

xyhw6mcr

xyhw6mcr6#

Patrik Stas' answer的基础上,如果你想做一个HTTP表单URL编码的POST,你必须做以下事情:在本例中,它是为了获得一个OAuth client_credentials令牌。
Cargo.toml

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

编码

use reqwest::{Client, Method};

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

async fn print_access_token() -> Result<()> {
    let client = Client::new();
    let host = "login.microsoftonline.com";
    let tenant = "TENANT";
    let client_id = "CLIENT_ID";
    let client_secret = "CLIENT_SECRET";
    let scope = "https://graph.microsoft.com/.default";
    let grant_type = "client_credentials";

    let url_string = format!("https://{}/{}/oauth2/v2.0/token", host, tenant);
    let body = format!(
        "client_id={}&client_secret={}&scope={}&grant_type={}",
        client_id, client_secret, scope, grant_type,
    );
    let req = client.request(Method::POST, &url_string).body(body);

    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<()> {
    print_access_token().await?;

    Ok(())
}

这将打印出如下内容。

200 OK
response: {"token_type":"Bearer","expires_in":3599,"ext_expires_in":3599,"access_token":"ACCESS_TOKEN"}
qij5mzcb

qij5mzcb7#

在此处放置使用surf机箱的版本(tide机箱的双重版本):

let res = surf::get("https://httpbin.org/get").await?;
assert_eq!(res.status(), 200);
liwlm1x9

liwlm1x98#

使用hyper“0.13”
还使用hyper-tls提供HTTPS支持。
文件 * 货物.toml*

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

代码

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

改编自https://hyper.rs/guides/client/basic/

qgelzfjb

qgelzfjb9#

使用此机箱的简单http请求:wsd

fn test() {
    wsd::http::get("https://docs.rs/", |data| {
        println!("status = {}, data = {}", data.status(), data.text());
    });
}

相关问题