HttpClient

Trait HttpClient 

Source
pub trait HttpClient: Send + Sync {
    // Required methods
    fn request<'life0, 'life1, 'life2, 'async_trait, T, R>(
        &'life0 self,
        method: Method,
        url: &'life1 str,
        headers: Option<HashMap<String, String>>,
        body: Option<&'life2 T>,
    ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
       where T: Serialize + Send + Sync + 'async_trait,
             R: for<'de> Deserialize<'de> + 'async_trait,
             Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait;
    fn request_with_retry<'life0, 'life1, 'life2, 'async_trait, T, R>(
        &'life0 self,
        method: Method,
        url: &'life1 str,
        headers: Option<HashMap<String, String>>,
        body: Option<&'life2 T>,
        _max_retries: u32,
    ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
       where T: Serialize + Send + Sync + Clone + 'async_trait,
             R: for<'de> Deserialize<'de> + 'async_trait,
             Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait;

    // Provided methods
    fn get<'life0, 'life1, 'async_trait, R>(
        &'life0 self,
        url: &'life1 str,
        headers: Option<HashMap<String, String>>,
    ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
       where R: for<'de> Deserialize<'de> + 'async_trait,
             Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait { ... }
    fn post<'life0, 'life1, 'life2, 'async_trait, T, R>(
        &'life0 self,
        url: &'life1 str,
        headers: Option<HashMap<String, String>>,
        body: &'life2 T,
    ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
       where T: Serialize + Send + Sync + 'async_trait,
             R: for<'de> Deserialize<'de> + 'async_trait,
             Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait { ... }
    fn put<'life0, 'life1, 'life2, 'async_trait, T, R>(
        &'life0 self,
        url: &'life1 str,
        headers: Option<HashMap<String, String>>,
        body: &'life2 T,
    ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
       where T: Serialize + Send + Sync + 'async_trait,
             R: for<'de> Deserialize<'de> + 'async_trait,
             Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait { ... }
}
Expand description

HTTP传输客户端抽象,定义通用HTTP操作接口

HTTP transport client abstraction defining generic HTTP operation interface

This trait defines the generic interface for all HTTP operations, allowing the adapter layer to avoid direct interaction with reqwest

Required Methods§

Source

fn request<'life0, 'life1, 'life2, 'async_trait, T, R>( &'life0 self, method: Method, url: &'life1 str, headers: Option<HashMap<String, String>>, body: Option<&'life2 T>, ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
where T: Serialize + Send + Sync + 'async_trait, R: for<'de> Deserialize<'de> + 'async_trait, Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Send HTTP request

Source

fn request_with_retry<'life0, 'life1, 'life2, 'async_trait, T, R>( &'life0 self, method: Method, url: &'life1 str, headers: Option<HashMap<String, String>>, body: Option<&'life2 T>, _max_retries: u32, ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
where T: Serialize + Send + Sync + Clone + 'async_trait, R: for<'de> Deserialize<'de> + 'async_trait, Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Send HTTP request with retry

Provided Methods§

Source

fn get<'life0, 'life1, 'async_trait, R>( &'life0 self, url: &'life1 str, headers: Option<HashMap<String, String>>, ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
where R: for<'de> Deserialize<'de> + 'async_trait, Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Send GET request

Examples found in repository?
examples/debug_openai_transport.rs (line 26)
6async fn main() -> Result<(), Box<dyn std::error::Error>> {
7    println!("🔍 OpenAI传输层调试");
8    println!("===================");
9    
10    let api_key = match std::env::var("OPENAI_API_KEY") {
11        Ok(key) => key,
12        Err(_) => {
13            println!("❌ 未设置OPENAI_API_KEY");
14            return Ok(());
15        }
16    };
17    
18    // 使用我们的HttpTransport
19    let transport = HttpTransport::new();
20    
21    // 测试GET请求 (模型列表) - 我们知道这个工作
22    println!("\n📋 测试GET请求 (模型列表):");
23    let mut headers = HashMap::new();
24    headers.insert("Authorization".to_string(), format!("Bearer {}", api_key));
25    
26    match transport.get::<serde_json::Value>("https://api.openai.com/v1/models", Some(headers)).await {
27        Ok(response) => {
28            let model_count = response["data"].as_array().map(|arr| arr.len()).unwrap_or(0);
29            println!("✅ GET请求成功,获取到 {} 个模型", model_count);
30        }
31        Err(e) => {
32            println!("❌ GET请求失败: {}", e);
33        }
34    }
35    
36    // 测试POST请求 (聊天完成) - 这个有问题
37    println!("\n💬 测试POST请求 (聊天完成):");
38    let mut headers = HashMap::new();
39    headers.insert("Authorization".to_string(), format!("Bearer {}", api_key));
40    
41    let request_body = json!({
42        "model": "gpt-3.5-turbo",
43        "messages": [
44            {
45                "role": "user",
46                "content": "Say 'test' in one word."
47            }
48        ],
49        "max_tokens": 5
50    });
51    
52    println!("请求体: {}", serde_json::to_string_pretty(&request_body)?);
53    
54    match transport.post::<serde_json::Value, serde_json::Value>(
55        "https://api.openai.com/v1/chat/completions",
56        Some(headers),
57        &request_body
58    ).await {
59        Ok(response) => {
60            println!("✅ POST请求成功!");
61            println!("响应: {}", serde_json::to_string_pretty(&response)?);
62        }
63        Err(e) => {
64            println!("❌ POST请求失败: {}", e);
65            
66            // 分析错误类型
67            let error_str = e.to_string();
68            if error_str.contains("you must provide a model parameter") {
69                println!("🔍 这个错误很奇怪,因为我们确实提供了model参数");
70                println!("   可能的原因:");
71                println!("   1. 代理服务器修改了请求体");
72                println!("   2. Content-Type头部问题");
73                println!("   3. JSON序列化问题");
74            }
75        }
76    }
77    
78    println!("\n💡 调试结论:");
79    println!("   • GET请求工作正常 → 认证和网络连接OK");
80    println!("   • POST请求失败 → 可能是代理或请求格式问题");
81    println!("   • 建议检查代理服务器的POST请求处理");
82    
83    Ok(())
84}
Source

fn post<'life0, 'life1, 'life2, 'async_trait, T, R>( &'life0 self, url: &'life1 str, headers: Option<HashMap<String, String>>, body: &'life2 T, ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
where T: Serialize + Send + Sync + 'async_trait, R: for<'de> Deserialize<'de> + 'async_trait, Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Send POST request

Examples found in repository?
examples/debug_openai_transport.rs (lines 54-58)
6async fn main() -> Result<(), Box<dyn std::error::Error>> {
7    println!("🔍 OpenAI传输层调试");
8    println!("===================");
9    
10    let api_key = match std::env::var("OPENAI_API_KEY") {
11        Ok(key) => key,
12        Err(_) => {
13            println!("❌ 未设置OPENAI_API_KEY");
14            return Ok(());
15        }
16    };
17    
18    // 使用我们的HttpTransport
19    let transport = HttpTransport::new();
20    
21    // 测试GET请求 (模型列表) - 我们知道这个工作
22    println!("\n📋 测试GET请求 (模型列表):");
23    let mut headers = HashMap::new();
24    headers.insert("Authorization".to_string(), format!("Bearer {}", api_key));
25    
26    match transport.get::<serde_json::Value>("https://api.openai.com/v1/models", Some(headers)).await {
27        Ok(response) => {
28            let model_count = response["data"].as_array().map(|arr| arr.len()).unwrap_or(0);
29            println!("✅ GET请求成功,获取到 {} 个模型", model_count);
30        }
31        Err(e) => {
32            println!("❌ GET请求失败: {}", e);
33        }
34    }
35    
36    // 测试POST请求 (聊天完成) - 这个有问题
37    println!("\n💬 测试POST请求 (聊天完成):");
38    let mut headers = HashMap::new();
39    headers.insert("Authorization".to_string(), format!("Bearer {}", api_key));
40    
41    let request_body = json!({
42        "model": "gpt-3.5-turbo",
43        "messages": [
44            {
45                "role": "user",
46                "content": "Say 'test' in one word."
47            }
48        ],
49        "max_tokens": 5
50    });
51    
52    println!("请求体: {}", serde_json::to_string_pretty(&request_body)?);
53    
54    match transport.post::<serde_json::Value, serde_json::Value>(
55        "https://api.openai.com/v1/chat/completions",
56        Some(headers),
57        &request_body
58    ).await {
59        Ok(response) => {
60            println!("✅ POST请求成功!");
61            println!("响应: {}", serde_json::to_string_pretty(&response)?);
62        }
63        Err(e) => {
64            println!("❌ POST请求失败: {}", e);
65            
66            // 分析错误类型
67            let error_str = e.to_string();
68            if error_str.contains("you must provide a model parameter") {
69                println!("🔍 这个错误很奇怪,因为我们确实提供了model参数");
70                println!("   可能的原因:");
71                println!("   1. 代理服务器修改了请求体");
72                println!("   2. Content-Type头部问题");
73                println!("   3. JSON序列化问题");
74            }
75        }
76    }
77    
78    println!("\n💡 调试结论:");
79    println!("   • GET请求工作正常 → 认证和网络连接OK");
80    println!("   • POST请求失败 → 可能是代理或请求格式问题");
81    println!("   • 建议检查代理服务器的POST请求处理");
82    
83    Ok(())
84}
Source

fn put<'life0, 'life1, 'life2, 'async_trait, T, R>( &'life0 self, url: &'life1 str, headers: Option<HashMap<String, String>>, body: &'life2 T, ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
where T: Serialize + Send + Sync + 'async_trait, R: for<'de> Deserialize<'de> + 'async_trait, Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Send PUT request

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§