83个版本 (40个稳定版本)
2.10.1 | 2024年8月8日 |
---|---|
2.10.0 | 2024年7月6日 |
2.9.7 | 2024年4月25日 |
2.9.6 | 2024年2月16日 |
0.4.5 | 2018年7月15日 |
#1 in HTTP客户端
1,568,594 每月下载量
在 1,634 个crate中 使用(831个直接使用)
355KB
6.5K SLoC
ureq
一个简单、安全的HTTP客户端。
Ureq的首要任务是易于使用。非常适合只需要完成任务的低开销HTTP客户端。与HTTP API配合得很好。其功能包括cookies、JSON、HTTP代理、HTTPS、与http
crate的互操作性和字符集解码。
Ureq是用纯Rust编写的,以确保安全和易于理解。它避免了直接使用unsafe
。它使用阻塞I/O而不是异步I/O,因为这可以使API简单,并保持依赖性最小。对于TLS,ureq使用rustls或native-tls。
有关最近发布版本的详细信息,请参阅变更日志。
使用方法
在其最简单的形式中,ureq看起来是这样的
fn main() -> Result<(), ureq::Error> {
let body: String = ureq::get("http://example.com")
.set("Example-Header", "header value")
.call()?
.into_string()?;
Ok(())
}
对于更复杂的任务,您可能需要创建一个Agent。Agent保留一个连接池以供重用,如果您使用“cookies”功能,则还包括cookie存储。由于内部Arc,Agent可以廉价地克隆,并且所有Agent的克隆之间共享状态。创建Agent还可以设置选项,如TLS配置。
use ureq::{Agent, AgentBuilder};
use std::time::Duration;
let agent: Agent = ureq::AgentBuilder::new()
.timeout_read(Duration::from_secs(5))
.timeout_write(Duration::from_secs(5))
.build();
let body: String = agent.get("http://example.com/page")
.call()?
.into_string()?;
// Reuses the connection from previous request.
let response: String = agent.put("http://example.com/upload")
.set("Authorization", "example-token")
.call()?
.into_string()?;
Ureq支持发送和接收JSON,如果您启用“json”功能
// Requires the `json` feature enabled.
let resp: String = ureq::post("http://myapi.example.com/ingest")
.set("X-My-Header", "Secret")
.send_json(ureq::json!({
"name": "martin",
"rust": true
}))?
.into_string()?;
错误处理
ureq通过Result<T, ureq::Error>
返回错误。这包括I/O错误、协议错误和状态码错误(当服务器响应4xx或5xx时)
use ureq::Error;
match ureq::get("http://mypage.example.com/").call() {
Ok(response) => { /* it worked */},
Err(Error::Status(code, response)) => {
/* the server returned an unexpected status
code (such as 400, 500 etc) */
}
Err(_) => { /* some kind of io/transport error */ }
}
有关Error类型的更多详细信息。
功能
为了启用最小依赖关系树,一些功能默认关闭。您可以在将ureq作为依赖项包含时控制它们。
ureq= {版本= "*",功能= ["json", "字符集"] }
tls
启用 https。默认情况下已启用。native-certs
使默认 TLS 实现使用操作系统的信任存储(见下面的 TLS 文档)。cookies
启用 cookies。json
通过 serde_json 启用 Response::into_json() 和 Request::send_json()。charset
启用解析 Content-Type 头的字符集部分(例如Content-Type: text/plain; charset=iso-8859-1
)。如果没有此选项,库默认使用 Rust 内置的utf-8
。socks-proxy
启用使用socks4://
、socks4a://
、socks5://
和socks://
(等于socks5://
)前缀的代理配置。native-tls
启用一个适配器,您可以将其native_tls::TlsConnector
实例传递给AgentBuilder::tls_connector
。由于存在意外切换到不受欢迎的 TLS 实现的风险,native-tls
从不被选中作为默认选项或由 crate 级便利调用(如ureq::get
等)使用 – 它必须在代理上配置。对于native-tls
,native-certs 功能不起作用。
gzip
启用请求 gzip 压缩的响应并对其进行解压缩。默认情况下已启用。brotli
启用请求 brotli 压缩的响应并对其进行解压缩。http-interop
启用从http::Response
和http::request::Builder
(v0.2)到和从的转换方法。http
启用从http::Response
和http::request::Builder
(v1.0)到和从的转换方法。
普通请求
大多数标准方法(GET、POST、PUT 等)作为库顶部的函数支持(get()、post()、put() 等)。
这些顶层 http 方法函数创建一个 Request 实例,它遵循构建模式。使用
.call()
无请求体完成构建器。.send()
请求体作为 Read(支持非已知大小的读取器的分块编码)。.send_string()
请求体作为字符串。.send_bytes()
将正文作为字节发送。.send_form()
将键值对作为 application/x-www-form-urlencoded 发送。
JSON
通过启用 ureq = { version = "*", features = ["json"] }
功能,库支持 serde json。
request.send_json()
将正文作为 serde json 发送。response.into_json()
将响应转换为 json。
内容长度和传输编码
在正文大小已知的请求中,库会发送 Content-Length 头部,换句话说,那些使用 .send_string()
、.send_bytes()
、.send_form()
或 .send_json()
发送的请求中,库会发送 Content-Length 头部。如果你发送一个正文大小未知的请求,使用 .send()
,它接受一个 Read,ureq 将发送 Transfer-Encoding: chunked,并相应地编码正文。无正文请求(GET 和 HEAD)使用 .call()
发送,ureq 不会添加 Content-Length 或 Transfer-Encoding 头部。
如果你在发送正文之前设置了 Content-Length 或 Transfer-Encoding 头部,ureq 会尊重该头部,不会覆盖它,并按照你设置的头部指示编码正文或不对正文进行编码。
let resp = ureq::post("http://my-server.com/ingest")
.set("Transfer-Encoding", "chunked")
.send_string("Hello world");
字符编码
通过启用 ureq = { version = "*", features = ["charset"] }
功能,库支持发送/接收除 utf-8 之外的其他字符集。
对于 response.into_string()
,我们读取头部 Content-Type: text/plain; charset=iso-8859-1
,如果其中包含字符集指定,我们尝试使用该编码解码正文。如果没有,或者无法解释字符集,我们将回退到 utf-8
。
类似地,当使用 request.send_string()
时,我们首先检查用户是否设置了 ; charset=<whatwg charset>
并尝试使用该编码对请求数据进行编码。
代理
ureq 支持两种代理类型,HTTP
(CONNECT
),SOCKS4
和 SOCKS5
,前者始终可用,而后者必须通过启用功能 ureq = { version = "*", features = ["socks-proxy"] }
来启用。
代理设置在 Agent 上配置(使用 [AgentBuilder])。所有通过该代理发送的请求都将进行代理。
使用 HTTP 的示例
fn proxy_example_1() -> std::result::Result<(), ureq::Error> {
// Configure an http connect proxy. Notice we could have used
// the http:// prefix here (it's optional).
let proxy = ureq::Proxy::new("user:[email protected]:9090")?;
let agent = ureq::AgentBuilder::new()
.proxy(proxy)
.build();
// This is proxied.
let resp = agent.get("http://cool.server").call()?;
Ok(())
}
使用 SOCKS5 的示例
fn proxy_example_2() -> std::result::Result<(), ureq::Error> {
// Configure a SOCKS proxy.
let proxy = ureq::Proxy::new("socks5://user:[email protected]:9090")?;
let agent = ureq::AgentBuilder::new()
.proxy(proxy)
.build();
// This is proxied.
let resp = agent.get("http://cool.server").call()?;
Ok(())
}
HTTPS / TLS / SSL
在支持 rustls 的平台上,ureq 使用 rustls。在其他平台上,可以使用 AgentBuilder::tls_connector
手动配置 native-tls。
如果您需要与只支持较不安全的 TLS 配置的服务器进行交互,则可能需要使用 native-tls。
以下是一个使用 native-tls 构建代理的示例。它需要启用 "native-tls" 功能。
use std::sync::Arc;
use ureq::Agent;
let agent = ureq::AgentBuilder::new()
.tls_connector(Arc::new(native_tls::TlsConnector::new()?))
.build();
受信任的根
当您使用 rustls(tls
功能)时,ureq 默认信任 webpki-roots,它是包含在您的程序中的 Mozilla 根计划的副本(因此,如果您的程序未更新,则不会更新)。您可以选择配置 rustls-native-certs,它从您的操作系统的信任存储中提取根。这意味着它将在您的操作系统更新时更新,并且它还将包括本地安装的根。
当您使用 native-tls
时,ureq 将使用您的操作系统证书验证器和根存储。
为了简单起见,使用阻塞 I/O
Ureq 使用阻塞 I/O 而不是 Rust 的新版 异步 (async) I/O。异步 I/O 允许在不增加内存和操作系统线程的高成本的情况下,服务多个并发请求。但是,这带来了复杂性。异步程序需要拉入运行时(通常是 async-std 或 tokio)。它们还需要任何可能阻塞的方法的异步版本,以及任何可能调用可能阻塞的另一个方法的任何方法的异步版本。这意味着异步程序通常有很多依赖项 - 这增加了编译时间,并增加了风险。
如果您正在编写一个必须以最小开销服务大量客户端的 HTTP 服务器,那么异步的成本是值得支付的。然而,对于 HTTP 客户端,我们认为这种成本通常不值得支付。异步 I/O 的低成本替代方案是阻塞 I/O,它有不同的价格:它需要为每个并发请求一个操作系统线程。然而,这个价格通常并不高:大多数 HTTP 客户端以顺序方式或低并发方式发出请求。
这就是为什么 ureq 使用阻塞 I/O 并计划保持这种方式。其他 HTTP 客户端提供异步 API 和阻塞 API,但我们想提供不带异步 API 所需所有依赖项的阻塞 API。
Ureq 受到其他优秀的 HTTP 客户端如 superagent 和 fetch API 的启发。
如果您正在寻找的不是 ureq,请查看这些其他 Rust HTTP 客户端:surf、reqwest、isahc、attohttpc、actix-web 和 hyper。
依赖项
~1–14MB
~231K SLoC