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§
Sourcefn 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<'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
Sourcefn 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,
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§
Sourcefn 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 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}
Sourcefn 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 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}
Sourcefn 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,
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.