mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-06-16 13:34:04 +08:00
fix(proxy): improve URL building and Gemini request handling
- Refactor URL construction with version path deduplication (/v1, /v1beta) - Preserve query parameters for Gemini API requests - Support GOOGLE_GEMINI_API_KEY field name (with fallback) - Change default proxy port from 5000 to 15721 - Fix test: use Option type for is_proxy_target field
This commit is contained in:
@@ -245,7 +245,7 @@ fn dry_run_validates_schema_compatibility() {
|
||||
meta: None,
|
||||
icon: None,
|
||||
icon_color: None,
|
||||
is_proxy_target: false,
|
||||
is_proxy_target: Some(false),
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -179,12 +179,8 @@ impl RequestForwarder {
|
||||
// 提取 base_url
|
||||
let base_url = self.extract_base_url(provider)?;
|
||||
|
||||
// 智能拼接 URL,避免重复的 /v1
|
||||
let url = if base_url.ends_with("/v1") && endpoint.starts_with("/v1") {
|
||||
format!("{}{}", base_url.trim_end_matches("/v1"), endpoint)
|
||||
} else {
|
||||
format!("{base_url}{endpoint}")
|
||||
};
|
||||
// 使用辅助函数构建完整 URL(自动去重版本路径)
|
||||
let url = self.build_full_url(&base_url, endpoint);
|
||||
|
||||
// 构建请求
|
||||
let mut request = self.client.post(&url);
|
||||
@@ -277,6 +273,28 @@ impl RequestForwarder {
|
||||
Ok(request)
|
||||
}
|
||||
|
||||
/// 构建完整 URL(智能去重版本路径)
|
||||
fn build_full_url(&self, base_url: &str, endpoint: &str) -> String {
|
||||
let base_trimmed = base_url.trim_end_matches('/');
|
||||
let endpoint_trimmed = endpoint.trim_start_matches('/');
|
||||
|
||||
// 检查是否存在版本路径重复
|
||||
let version_patterns = ["/v1beta", "/v1"];
|
||||
let mut final_url = format!("{base_trimmed}/{endpoint_trimmed}");
|
||||
|
||||
for pattern in &version_patterns {
|
||||
let duplicate_pattern = format!("{pattern}{pattern}");
|
||||
if final_url.contains(&duplicate_pattern) {
|
||||
final_url = final_url.replace(&duplicate_pattern, pattern);
|
||||
log::debug!(
|
||||
"URL 去重: 移除重复的 {pattern} (base: {base_url}, endpoint: {endpoint})"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final_url
|
||||
}
|
||||
|
||||
/// 从 Provider 配置中提取 base_url
|
||||
fn extract_base_url(&self, provider: &Provider) -> Result<String, ProxyError> {
|
||||
log::debug!("Extracting base_url for provider: {}", provider.name);
|
||||
@@ -370,8 +388,12 @@ impl RequestForwarder {
|
||||
return Some((key.to_string(), AuthType::Anthropic));
|
||||
}
|
||||
|
||||
// Gemini
|
||||
if let Some(key) = env.get("GEMINI_API_KEY").and_then(|v| v.as_str()) {
|
||||
// Gemini (支持两种字段名,优先使用标准的 GOOGLE_GEMINI_API_KEY)
|
||||
if let Some(key) = env
|
||||
.get("GOOGLE_GEMINI_API_KEY")
|
||||
.or_else(|| env.get("GEMINI_API_KEY"))
|
||||
.and_then(|v| v.as_str())
|
||||
{
|
||||
return Some((key.to_string(), AuthType::Gemini));
|
||||
}
|
||||
|
||||
@@ -540,11 +562,7 @@ impl RequestForwarder {
|
||||
headers: &axum::http::HeaderMap,
|
||||
) -> Result<Response, ProxyError> {
|
||||
let base_url = self.extract_base_url(provider)?;
|
||||
let url = if base_url.ends_with("/v1") && endpoint.starts_with("/v1") {
|
||||
format!("{}{}", base_url.trim_end_matches("/v1"), endpoint)
|
||||
} else {
|
||||
format!("{base_url}{endpoint}")
|
||||
};
|
||||
let url = self.build_full_url(&base_url, endpoint);
|
||||
|
||||
log::info!("Proxy GET Request URL: {url}");
|
||||
|
||||
@@ -599,11 +617,7 @@ impl RequestForwarder {
|
||||
headers: &axum::http::HeaderMap,
|
||||
) -> Result<Response, ProxyError> {
|
||||
let base_url = self.extract_base_url(provider)?;
|
||||
let url = if base_url.ends_with("/v1") && endpoint.starts_with("/v1") {
|
||||
format!("{}{}", base_url.trim_end_matches("/v1"), endpoint)
|
||||
} else {
|
||||
format!("{base_url}{endpoint}")
|
||||
};
|
||||
let url = self.build_full_url(&base_url, endpoint);
|
||||
|
||||
log::info!("Proxy DELETE Request URL: {url}");
|
||||
|
||||
|
||||
@@ -93,10 +93,10 @@ pub async fn handle_count_tokens(
|
||||
Ok(builder.body(body).unwrap())
|
||||
}
|
||||
|
||||
/// 处理 Gemini API 请求(透传)
|
||||
/// 处理 Gemini API 请求(透传,包括查询参数)
|
||||
pub async fn handle_gemini(
|
||||
State(state): State<ProxyState>,
|
||||
axum::extract::Path(path): axum::extract::Path<String>,
|
||||
uri: axum::http::Uri,
|
||||
headers: axum::http::HeaderMap,
|
||||
Json(body): Json<Value>,
|
||||
) -> Result<axum::response::Response, ProxyError> {
|
||||
@@ -108,9 +108,16 @@ pub async fn handle_gemini(
|
||||
state.status.clone(),
|
||||
);
|
||||
|
||||
let endpoint = format!("/{path}");
|
||||
// 提取完整的路径和查询参数
|
||||
let endpoint = uri
|
||||
.path_and_query()
|
||||
.map(|pq| pq.as_str())
|
||||
.unwrap_or(uri.path());
|
||||
|
||||
log::debug!("Gemini request endpoint (with query): {endpoint}");
|
||||
|
||||
let response = forwarder
|
||||
.forward_with_retry(&AppType::Gemini, &endpoint, body, headers)
|
||||
.forward_with_retry(&AppType::Gemini, endpoint, body, headers)
|
||||
.await?;
|
||||
|
||||
// 透传响应
|
||||
|
||||
@@ -22,7 +22,7 @@ impl Default for ProxyConfig {
|
||||
Self {
|
||||
enabled: false,
|
||||
listen_address: "127.0.0.1".to_string(),
|
||||
listen_port: 5000,
|
||||
listen_port: 15721, // 使用较少占用的高位端口
|
||||
max_retries: 3,
|
||||
request_timeout: 300,
|
||||
enable_logging: true,
|
||||
|
||||
Reference in New Issue
Block a user