File size: 1,394 Bytes
c55968e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//! 连接池:进程级单例 `reqwest::Client`。
//!
//! 每次新建 client = 每条请求都白付一次 TCP + TLS 握手(几十到几百 ms)。
//! 做成单例后,第二条请求起直接复用连接 → 流式首 token 明显提前。
//!
//! 注意:`reqwest::Client` 内部的连接池是**按 client 实例**管理的,
//! 所以一定要复用同一个实例,而不是每次请求 new 一个。

use std::sync::OnceLock;
use std::time::Duration;

/// 全局单例 HTTP 客户端(首次调用时懒初始化,之后复用)。
///
/// 失败会返回错误字符串——调用方可以降级为一次性 client。
pub fn shared_client() -> Result<reqwest::Client, String> {
    static CLIENT: OnceLock<Result<reqwest::Client, String>> = OnceLock::new();
    CLIENT
        .get_or_init(|| {
            reqwest::Client::builder()
                // 保留空闲连接,供后续请求复用(keep-alive)
                .pool_max_idle_per_host(8)
                .pool_idle_timeout(Duration::from_secs(90))
                .tcp_keepalive(Duration::from_secs(30))
                // 启用压缩:减少下行字节,流式正文更早到
                .gzip(true)
                .brotli(true)
                .deflate(true)
                .build()
                .map_err(|e| format!("初始化 HTTP 客户端失败:{e}"))
        })
        .clone()
}