HttpTransport

Struct HttpTransport 

Source
pub struct HttpTransport { /* private fields */ }
Expand description

基于reqwest的HTTP传输实现,封装所有HTTP细节

HTTP transport implementation based on reqwest, encapsulating all HTTP details

This is the concrete implementation of the HttpClient trait, encapsulating all HTTP details

Implementations§

Source§

impl HttpTransport

Source

pub fn new() -> Self

Create new HTTP transport instance

Automatically detects AI_PROXY_URL environment variable for proxy configuration

Examples found in repository?
examples/debug_openai_transport.rs (line 19)
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

pub fn with_timeout(timeout: Duration) -> Self

Create HTTP transport instance with timeout

Automatically detects AI_PROXY_URL environment variable for proxy configuration

Source

pub fn with_proxy( timeout: Duration, proxy_url: Option<&str>, ) -> Result<Self, TransportError>

Create HTTP transport instance with custom proxy

Source

pub fn timeout(&self) -> Duration

Get current timeout setting

Source§

impl HttpTransport

Source

pub fn boxed(self) -> DynHttpTransportRef

Produce an Arc-wrapped object-safe transport reference

Trait Implementations§

Source§

impl Default for HttpTransport

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl HttpClient for HttpTransport

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
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
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
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

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,