diff --git a/src-tauri/src/providers/claude_custom.rs b/src-tauri/src/providers/claude_custom.rs index 50167bcd1..23d4264a9 100644 --- a/src-tauri/src/providers/claude_custom.rs +++ b/src-tauri/src/providers/claude_custom.rs @@ -4,6 +4,7 @@ use crate::models::openai::{ChatCompletionRequest, ContentPart, MessageContent}; use reqwest::Client; use serde::{Deserialize, Serialize}; use std::error::Error; +use std::time::Duration; #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct ClaudeCustomConfig { @@ -17,11 +18,26 @@ pub struct ClaudeCustomProvider { pub client: Client, } +/// 创建配置好的 HTTP 客户端 +/// +/// 配置说明: +/// - connect_timeout: 连接超时 30 秒 +/// - timeout: 总超时 10 分钟(流式响应可能很长) +/// - 不设置 pool_idle_timeout 以保持连接活跃 +fn create_http_client() -> Client { + Client::builder() + .connect_timeout(Duration::from_secs(30)) + .timeout(Duration::from_secs(600)) // 10 分钟总超时,支持长时间流式响应 + .tcp_keepalive(Duration::from_secs(60)) // TCP keepalive 保持连接活跃 + .build() + .unwrap_or_else(|_| Client::new()) +} + impl Default for ClaudeCustomProvider { fn default() -> Self { Self { config: ClaudeCustomConfig::default(), - client: Client::new(), + client: create_http_client(), } } } @@ -39,7 +55,7 @@ impl ClaudeCustomProvider { base_url, enabled: true, }, - client: Client::new(), + client: create_http_client(), } } diff --git a/src-tauri/src/server/handlers/provider_calls.rs b/src-tauri/src/server/handlers/provider_calls.rs index ac8ca9770..16efe4cda 100644 --- a/src-tauri/src/server/handlers/provider_calls.rs +++ b/src-tauri/src/server/handlers/provider_calls.rs @@ -611,8 +611,10 @@ pub async fn call_provider_anthropic( return Response::builder() .status(StatusCode::OK) .header(header::CONTENT_TYPE, "text/event-stream") - .header(header::CACHE_CONTROL, "no-cache") + .header(header::CACHE_CONTROL, "no-cache, no-store, must-revalidate") .header("Connection", "keep-alive") + .header("X-Accel-Buffering", "no") // 禁用 nginx 等代理的缓冲 + .header("Transfer-Encoding", "chunked") .body(Body::from_stream(stream)) .unwrap_or_else(|_| { ( @@ -823,8 +825,10 @@ pub async fn call_provider_anthropic( return Response::builder() .status(StatusCode::OK) .header(header::CONTENT_TYPE, "text/event-stream") - .header(header::CACHE_CONTROL, "no-cache") + .header(header::CACHE_CONTROL, "no-cache, no-store, must-revalidate") .header("Connection", "keep-alive") + .header("X-Accel-Buffering", "no") // 禁用 nginx 等代理的缓冲 + .header("Transfer-Encoding", "chunked") .body(Body::from_stream(stream)) .unwrap_or_else(|_| { ( @@ -1834,8 +1838,10 @@ pub async fn call_provider_openai( return Response::builder() .status(StatusCode::OK) .header(header::CONTENT_TYPE, "text/event-stream") - .header(header::CACHE_CONTROL, "no-cache") + .header(header::CACHE_CONTROL, "no-cache, no-store, must-revalidate") .header("Connection", "keep-alive") + .header("X-Accel-Buffering", "no") // 禁用 nginx 等代理的缓冲 + .header("Transfer-Encoding", "chunked") .body(Body::from_stream(stream)) .unwrap_or_else(|_| { (