3

ureq:Rust中一个简单、安全的、阻塞 I/O的HTTP客户端

 1 year ago
source link: https://www.jdon.com/67096.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

ureq:Rust中一个简单、安全的、阻塞 I/O的HTTP客户端

Ureq 的首要任务是易于使用。对于任何想要一个低开销的 HTTP 客户端来完成工作的人来说,它非常有用。与 HTTP API 配合得很好。其功能包括 cookie、JSON、HTTP 代理、HTTPS、http与 crate 的互操作性以及字符集解码。

为了安全性和易于理解,Ureq 采用纯 Rust 语言。它避免了 unsafe直接使用。它使用阻塞 I/O而不是异步 I/O,因为这样可以保持 API 简单并将依赖关系降至最低。对于 TLS,ureq 使用 rustls 或 native-tls。

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 看起来像这样:

fn main() -> Result<(), ureq::Error> {
    let body: String = ureq::get("http://example.com")
        .set("Example-Header", "header value")
        .call()?
        .into_string()?;
    Ok(())
}

对于更多涉及的任务,您需要创建一个Agent。代理拥有一个连接池以供重用,如果您使用“cookies”功能,则还拥有一个 cookie 存储区。由于存在内部 Arc,并且 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()?;

如果启用“json”功能,Ureq 支持发送和接收 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 */ }
}

使用 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 配置的服务器进行互操作(例如,rustls 不支持 TLS 1.0 和 1.1),您可能需要使用 native-tls。如果您需要验证 IP 地址的证书(目前 rustls 不支持),您可能还想使用它。

下面是构建使用 native-tls 的 Agent 的示例。它需要启用“native-tls”功能。

  use std::sync::Arc;
  use ureq::Agent;

  let agent = ureq::AgentBuilder::new()
      .tls_connector(Arc::new(native_tls::TlsConnector::new()?))
      .build();

点击标题



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK