我如何从Rust发出HTTP请求?我似乎在核心库中找不到任何东西。我不需要解析输出,只需要发出请求并检查HTTP响应代码。如果有人能告诉我如何对我的URL上的查询参数进行URL编码,那就更好了!
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(())}
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中:
Cargo.toml
[dependencies]reqwest = { version = "0.11", features = ["blocking"] }
[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(())}
# [tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let resp = reqwest::get("https://httpbin.org/ip")
.await?
.text()
.await?;
[dependencies]reqwest = "0.11"tokio = { version = "1", features = ["full"] }
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);}
use hyper::{body::HttpBody as _, Client, Uri};
let client = Client::new();
let res = client
.get(Uri::from_static("http://httpbin.org/ip"))
println!("status: {}", res.status());
let buf = hyper::body::to_bytes(res).await?;
println!("body: {:?}", buf);
[dependencies]hyper = { version = "0.14", features = ["full"] }tokio = { version = "1", features = ["full"] }
hyper = { version = "0.14", features = ["full"] }
我相信你正在寻找的是在standard library中。现在在rust-http中,Chris Morgan的答案是在可预见的未来当前Rust中的标准方式。我不确定我能带你走多远(希望我没有带你走错方向!),但你会想要这样的东西:
// Rust 0.6 -- old codeextern 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));}
// 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的单元测试中有一些示例。
dsf9zpds2#
我一直在研究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); }}
extern mod http;
use http::client::RequestWriter;
use http::method::Get;
use http::status;
use std::os;
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)]).适当的函数进行转换:
src/examples/client/client.rs
extra::url::Query
~[(~str, ~str)]
extra::url::query_to_str
extra::url::query_from_str
yptwkmov3#
使用卷边装订。把这个贴在你的Cargo.toml上:
[dependencies.curl]git = "https://github.com/carllerche/curl-rust"
[dependencies.curl]
git = "https://github.com/carllerche/curl-rust"
......而src/main.rs中的这个:
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()); }
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());
ojsjcaue4#
我更喜欢低依赖计数的板条箱,所以我会推荐这些:
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(())}
use minreq;
fn main() -> Result<(), minreq::Error> {
let o = minreq::get("https://speedtest.lax.hivelocity.net").send()?;
let s = o.as_str()?;
print!("{}", s);
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(())}
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)?;
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"] }
[package]
name = "play_async"
version = "0.1.0"
edition = "2018"
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(())}
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 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);
async fn main() -> Result<()> {
post_greeting().await?;
进入https://webhook.site,创建你的webhook链接,修改代码,你会看到服务器实时收到请求。此示例最初基于Bastian Gruber's example,并已针对现代Rust语法和更新的crate版本进行了更新。
xyhw6mcr6#
在Patrik Stas' answer的基础上,如果你想做一个HTTP表单URL编码的POST,你必须做以下事情:在本例中,它是为了获得一个OAuth client_credentials令牌。Cargo.toml
client_credentials
[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(())}
use reqwest::{Client, Method};
async fn print_access_token() -> Result<()> {
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);
print_access_token().await?;
这将打印出如下内容。
200 OKresponse: {"token_type":"Bearer","expires_in":3599,"ext_expires_in":3599,"access_token":"ACCESS_TOKEN"}
200 OK
response: {"token_type":"Bearer","expires_in":3599,"ext_expires_in":3599,"access_token":"ACCESS_TOKEN"}
qij5mzcb7#
在此处放置使用surf机箱的版本(tide机箱的双重版本):
surf
tide
let res = surf::get("https://httpbin.org/get").await?;assert_eq!(res.status(), 200);
let res = surf::get("https://httpbin.org/get").await?;
assert_eq!(res.status(), 200);
liwlm1x98#
使用hyper“0.13”还使用hyper-tls提供HTTPS支持。文件 * 货物.toml*
hyper = "0.13"hyper-tls = "0.4.1"tokio = { version = "0.2", features = ["full"] }
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(())}
extern crate hyper;
use hyper::Client;
use hyper::body::HttpBody as _;
use tokio::io::{stdout, AsyncWriteExt as _};
use hyper_tls::HttpsConnector;
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?;
改编自https://hyper.rs/guides/client/basic/
qgelzfjb9#
使用此机箱的简单http请求:wsd
fn test() { wsd::http::get("https://docs.rs/", |data| { println!("status = {}, data = {}", data.status(), data.text()); });}
fn test() {
wsd::http::get("https://docs.rs/", |data| {
println!("status = {}, data = {}", data.status(), data.text());
});
9条答案
按热度按时间s4n0splo1#
在Rust中发出HTTP请求最简单的方法是使用reqwest crate:
在
Cargo.toml
中:异步
Reqwest还支持使用Tokio发出 * 异步 * HTTP请求:
在
Cargo.toml
中:超级
Reqwest是Hyper的一个简单易用的 Package 器,Hyper是Rust的一个流行的HTTP库。如果你需要更多的控制来管理连接,你可以直接使用它。下面是一个基于Hyper的例子,它很大程度上受到了an example in its documentation的启发:
在
Cargo.toml
中:原始答案(生 rust 0.6)
我相信你正在寻找的是在standard library中。现在在rust-http中,Chris Morgan的答案是在可预见的未来当前Rust中的标准方式。我不确定我能带你走多远(希望我没有带你走错方向!),但你会想要这样的东西:
至于编码,在src/libstd/net_url. rs的单元测试中有一些示例。
dsf9zpds2#
更新:这个答案涉及到相当古老的历史。对于当前的最佳实践,请改为查看Isaac Aggrey's answer。
我一直在研究rust-http,它已经成为Rust的 * 事实上的 * HTTP库(Servo使用它);它还远远不够完整,目前的文档记录也非常少。下面是一个使用状态代码发出请求并执行操作的示例:
使用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)]
).适当的函数进行转换:extra::url::query_to_str
extra::url::query_from_str
(抱歉,目前不能使用,因为它是私人的。公关即将公开。同时,这个链接实际上不应该工作,它是因为https://github.com/mozilla/rust/issues/7476才可用的。)yptwkmov3#
使用卷边装订。把这个贴在你的
Cargo.toml
上:......而
src/main.rs
中的这个:ojsjcaue4#
我更喜欢低依赖计数的板条箱,所以我会推荐这些:
MinReq(0个深度)
HTTP_Req(35个深度)
6yt4nkrj5#
为了详细说明Isaac Aggrey's answer,下面是一个使用reqwest库生成带有查询参数的POST请求的示例。
Cargo.toml
编码
进入https://webhook.site,创建你的webhook链接,修改代码,你会看到服务器实时收到请求。
此示例最初基于Bastian Gruber's example,并已针对现代Rust语法和更新的crate版本进行了更新。
xyhw6mcr6#
在Patrik Stas' answer的基础上,如果你想做一个HTTP表单URL编码的POST,你必须做以下事情:在本例中,它是为了获得一个OAuth
client_credentials
令牌。Cargo.toml
编码
这将打印出如下内容。
qij5mzcb7#
在此处放置使用
surf
机箱的版本(tide
机箱的双重版本):liwlm1x98#
使用hyper“0.13”
还使用hyper-tls提供HTTPS支持。
文件 * 货物.toml*
代码
改编自https://hyper.rs/guides/client/basic/
qgelzfjb9#
使用此机箱的简单http请求:wsd