Skip to main content

x_one/xhttp/
client.rs

1//! xhttp 对外 API
2//!
3//! 提供全局 HTTP 客户端和便捷请求方法。
4//!
5//! ```ignore
6//! // 使用便捷方法
7//! let resp = x_one::xhttp::get("https://api.example.com/users")
8//!     .header("X-Token", "abc")
9//!     .send()
10//!     .await?;
11//!
12//! // 获取底层 client 做更复杂操作
13//! let client = x_one::xhttp::c();
14//! ```
15
16use super::config::XHttpConfig;
17use crate::xutil;
18use std::sync::OnceLock;
19use std::time::Duration;
20
21/// 全局 HTTP 客户端
22pub(crate) static HTTP_CLIENT: OnceLock<reqwest::Client> = OnceLock::new();
23
24/// 获取全局 HTTP 客户端引用
25///
26/// 框架初始化后返回按配置构建的 client;
27/// 初始化前访问会使用默认配置并输出警告。
28pub fn c() -> &'static reqwest::Client {
29    HTTP_CLIENT.get_or_init(|| {
30        xutil::warn_if_enable_debug(
31            "XHttp client accessed before init, using default configuration",
32        );
33        reqwest::Client::new()
34    })
35}
36
37/// 根据配置构建 `reqwest::Client`
38///
39/// 内部初始化使用,支持 timeout、connect_timeout、keep_alive、连接池等参数。
40pub fn build_client(config: &XHttpConfig) -> Result<reqwest::Client, crate::error::XOneError> {
41    let timeout = duration_or(&config.timeout, Duration::from_secs(30));
42    let connect_timeout = duration_or(&config.dial_timeout, Duration::from_secs(10));
43    let keep_alive = duration_or(&config.dial_keep_alive, Duration::from_secs(30));
44
45    let builder = reqwest::Client::builder()
46        .timeout(timeout)
47        .connect_timeout(connect_timeout)
48        .pool_max_idle_per_host(config.pool_max_idle_per_host)
49        .tcp_keepalive(keep_alive);
50
51    builder
52        .build()
53        .map_err(|e| crate::error::XOneError::Other(format!("XHttp build client failed: {e}")))
54}
55
56fn duration_or(value: &str, default: Duration) -> Duration {
57    xutil::to_duration(value).unwrap_or(default)
58}
59
60// ---- 便捷方法,直接使用全局 client 发起请求 ----
61
62/// 发起 GET 请求
63pub fn get(url: &str) -> reqwest::RequestBuilder {
64    c().get(url)
65}
66
67/// 发起 POST 请求
68pub fn post(url: &str) -> reqwest::RequestBuilder {
69    c().post(url)
70}
71
72/// 发起 PUT 请求
73pub fn put(url: &str) -> reqwest::RequestBuilder {
74    c().put(url)
75}
76
77/// 发起 PATCH 请求
78pub fn patch(url: &str) -> reqwest::RequestBuilder {
79    c().patch(url)
80}
81
82/// 发起 DELETE 请求
83pub fn delete(url: &str) -> reqwest::RequestBuilder {
84    c().delete(url)
85}
86
87/// 发起 HEAD 请求
88pub fn head(url: &str) -> reqwest::RequestBuilder {
89    c().head(url)
90}