From 1c46bb547b2924967c69b013071170a427461788 Mon Sep 17 00:00:00 2001 From: hex2077 Date: Wed, 10 Dec 2025 15:45:08 +0800 Subject: [PATCH] =?UTF-8?q?perf(api):=20=E4=B8=BA=E6=89=80=E6=9C=89API?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E6=B7=BB=E5=8A=A0HTTP=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E6=B1=A0=E9=85=8D=E7=BD=AE=E9=98=B2=E6=AD=A2=E8=B5=84=E6=BA=90?= =?UTF-8?q?=E6=B3=84=E6=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 为Claude、OpenAI、Gemini、Qwen等API服务添加HTTP/HTTPS agent配置,设置keepAlive、maxSockets等参数以限制连接池大小,避免资源泄漏问题。同时统一了各服务的axios配置方式,提高网络请求的稳定性和性能。 --- src/claude/claude-core.js | 18 ++++++++++++++ src/claude/claude-kiro.js | 6 ++--- src/gemini/antigravity-core.js | 24 ++++++++++++++++++- src/gemini/gemini-core.js | 24 ++++++++++++++++++- src/openai/openai-core.js | 18 ++++++++++++++ src/openai/openai-responses-core.js | 33 ++++++++++++++++++++++--- src/openai/qwen-core.js | 37 ++++++++++++++++++++++++++--- 7 files changed, 149 insertions(+), 11 deletions(-) diff --git a/src/claude/claude-core.js b/src/claude/claude-core.js index 13273cd..01789d2 100644 --- a/src/claude/claude-core.js +++ b/src/claude/claude-core.js @@ -1,4 +1,6 @@ import axios from 'axios'; +import * as http from 'http'; +import * as https from 'https'; /** * Claude API Core Service Class. @@ -27,8 +29,24 @@ export class ClaudeApiService { * @returns {object} Axios instance. */ createClient() { + // 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 + const httpAgent = new http.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const httpsAgent = new https.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const axiosConfig = { baseURL: this.baseUrl, + httpAgent, + httpsAgent, headers: { 'x-api-key': this.apiKey, 'Content-Type': 'application/json', diff --git a/src/claude/claude-kiro.js b/src/claude/claude-kiro.js index 7e08576..bce1a17 100644 --- a/src/claude/claude-kiro.js +++ b/src/claude/claude-kiro.js @@ -308,15 +308,15 @@ export class KiroApiService { // 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 const httpAgent = new http.Agent({ keepAlive: true, - maxSockets: 200, // 每个主机最多 10 个连接 + maxSockets: 100, // 每个主机最多 10 个连接 maxFreeSockets: 5, // 最多保留 5 个空闲连接 - timeout: 60000, // 空闲连接 60 秒后关闭 + timeout: 120000, // 空闲连接 60 秒后关闭 }); const httpsAgent = new https.Agent({ keepAlive: true, maxSockets: 100, maxFreeSockets: 5, - timeout: 60000, + timeout: 120000, }); const axiosConfig = { diff --git a/src/gemini/antigravity-core.js b/src/gemini/antigravity-core.js index 7692232..0c10915 100644 --- a/src/gemini/antigravity-core.js +++ b/src/gemini/antigravity-core.js @@ -1,5 +1,6 @@ import { OAuth2Client } from 'google-auth-library'; import * as http from 'http'; +import * as https from 'https'; import { promises as fs } from 'fs'; import * as path from 'path'; import * as os from 'os'; @@ -9,6 +10,20 @@ import open from 'open'; import { API_ACTIONS, formatExpiryTime } from '../common.js'; import { getProviderModels } from '../provider-models.js'; +// 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 +const httpAgent = new http.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, +}); +const httpsAgent = new https.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, +}); + // --- Constants --- const AUTH_REDIRECT_PORT = 8086; const CREDENTIALS_DIR = '.antigravity'; @@ -210,7 +225,14 @@ function ensureRolesInContents(requestBody) { export class AntigravityApiService { constructor(config) { - this.authClient = new OAuth2Client(OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET); + // 配置 OAuth2Client 使用自定义的 HTTP agent + this.authClient = new OAuth2Client({ + clientId: OAUTH_CLIENT_ID, + clientSecret: OAUTH_CLIENT_SECRET, + transporterOptions: { + agent: httpsAgent, + }, + }); this.availableModels = []; this.isInitialized = false; diff --git a/src/gemini/gemini-core.js b/src/gemini/gemini-core.js index eee6791..fa0adf0 100644 --- a/src/gemini/gemini-core.js +++ b/src/gemini/gemini-core.js @@ -1,5 +1,6 @@ import { OAuth2Client } from 'google-auth-library'; import * as http from 'http'; +import * as https from 'https'; import { promises as fs } from 'fs'; import * as path from 'path'; import * as os from 'os'; @@ -8,6 +9,20 @@ import open from 'open'; import { API_ACTIONS, formatExpiryTime } from '../common.js'; import { getProviderModels } from '../provider-models.js'; +// 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 +const httpAgent = new http.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, +}); +const httpsAgent = new https.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, +}); + // --- Constants --- const AUTH_REDIRECT_PORT = 8085; const CREDENTIALS_DIR = '.gemini'; @@ -177,7 +192,14 @@ async function* apply_anti_truncation_to_stream(service, model, requestBody) { export class GeminiApiService { constructor(config) { - this.authClient = new OAuth2Client(OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET); + // 配置 OAuth2Client 使用自定义的 HTTP agent + this.authClient = new OAuth2Client({ + clientId: OAUTH_CLIENT_ID, + clientSecret: OAUTH_CLIENT_SECRET, + transporterOptions: { + agent: httpsAgent, + }, + }); this.availableModels = []; this.isInitialized = false; diff --git a/src/openai/openai-core.js b/src/openai/openai-core.js index e966f62..ad77b90 100644 --- a/src/openai/openai-core.js +++ b/src/openai/openai-core.js @@ -1,4 +1,6 @@ import axios from 'axios'; +import * as http from 'http'; +import * as https from 'https'; // Assumed OpenAI API specification service for interacting with third-party models export class OpenAIApiService { @@ -12,8 +14,24 @@ export class OpenAIApiService { this.useSystemProxy = config?.USE_SYSTEM_PROXY_OPENAI ?? false; console.log(`[OpenAI] System proxy ${this.useSystemProxy ? 'enabled' : 'disabled'}`); + // 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 + const httpAgent = new http.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const httpsAgent = new https.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const axiosConfig = { baseURL: this.baseUrl, + httpAgent, + httpsAgent, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.apiKey}` diff --git a/src/openai/openai-responses-core.js b/src/openai/openai-responses-core.js index 9052acc..80e15c5 100644 --- a/src/openai/openai-responses-core.js +++ b/src/openai/openai-responses-core.js @@ -1,4 +1,6 @@ import axios from 'axios'; +import * as http from 'http'; +import * as https from 'https'; // OpenAI Responses API specification service for interacting with third-party models export class OpenAIResponsesApiService { @@ -9,14 +11,39 @@ export class OpenAIResponsesApiService { this.config = config; this.apiKey = config.OPENAI_API_KEY; this.baseUrl = config.OPENAI_BASE_URL || 'https://api.openai.com/v1'; - // console.log(`[OpenAIResponsesApiService] Base URL: ${JSON.stringify(config)}`); - this.axiosInstance = axios.create({ + this.useSystemProxy = config?.USE_SYSTEM_PROXY_OPENAI ?? false; + console.log(`[OpenAIResponses] System proxy ${this.useSystemProxy ? 'enabled' : 'disabled'}`); + + // 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 + const httpAgent = new http.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const httpsAgent = new https.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + + const axiosConfig = { baseURL: this.baseUrl, + httpAgent, + httpsAgent, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.apiKey}` } - }); + }; + + // 禁用系统代理以避免HTTPS代理错误 + if (!this.useSystemProxy) { + axiosConfig.proxy = false; + } + + this.axiosInstance = axios.create(axiosConfig); } async callApi(endpoint, body, isRetry = false, retryCount = 0) { diff --git a/src/openai/qwen-core.js b/src/openai/qwen-core.js index c830d90..61dc65b 100644 --- a/src/openai/qwen-core.js +++ b/src/openai/qwen-core.js @@ -3,6 +3,8 @@ import crypto from 'crypto'; import path from 'node:path'; import { promises as fs, unlinkSync } from 'node:fs'; import * as os from 'os'; +import * as http from 'http'; +import * as https from 'https'; import open from 'open'; import { EventEmitter } from 'events'; import { randomUUID } from 'node:crypto'; @@ -187,13 +189,28 @@ export class QwenApiService { console.log('[Qwen] Initializing Qwen API Service...'); await this._initializeAuth(); + // 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 + const httpAgent = new http.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const httpsAgent = new https.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const axiosConfig = { baseURL: DEFAULT_QWEN_BASE_URL, + httpAgent, + httpsAgent, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer `, }, - }; // 禁用系统代理 @@ -501,8 +518,24 @@ export class QwenApiService { try { const { token, endpoint: qwenBaseUrl } = await this.getValidToken(); + // 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 + const httpAgent = new http.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const httpsAgent = new https.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const axiosConfig = { baseURL: qwenBaseUrl, + httpAgent, + httpsAgent, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, @@ -510,8 +543,6 @@ export class QwenApiService { 'X-DashScope-UserAgent': userAgent, 'X-DashScope-AuthType': 'qwen-oauth', }, - // 添加 HTTPS 代理修复相关配置 - httpsAgent: undefined, // axios-https-proxy-fix 会自动处理 }; // 禁用系统代理