diff --git a/src/api-server.js b/src/api-server.js index a8cb2ef..f02873d 100644 --- a/src/api-server.js +++ b/src/api-server.js @@ -450,7 +450,7 @@ async function initApiService(config) { providerPoolManager = new ProviderPoolManager(config.providerPools, { globalConfig: config }); console.log('[Initialization] ProviderPoolManager initialized with configured pools.'); // 可以选择在这里触发一次健康检查 - providerPoolManager.performHealthChecks(); + providerPoolManager.performHealthChecks(true); } else { console.log('[Initialization] No provider pools configured. Using single provider mode.'); } @@ -555,10 +555,45 @@ function createRequestHandler(config) { return async function requestHandler(req, res) { // Deep copy the config for each request to allow dynamic modification const currentConfig = deepmerge({}, config); - console.log(`\n${new Date().toLocaleString()}`); console.log(`[Server] Received request: ${req.method} http://${req.headers.host}${req.url}`); + const requestUrl = new URL(req.url, `http://${req.headers.host}`); + let path = requestUrl.pathname; + + const method = req.method; + if (method === 'OPTIONS') { + // 设置 CORS 头部,允许所有来源和方法 + res.setHeader('Access-Control-Allow-Origin', '*'); + res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); + res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-goog-api-key, Model-Provider'); // 添加 Model-Provider + + // OPTIONS 请求通常返回 204 No Content + res.writeHead(204); + res.end(); + return; + } + + // Health check endpoint - no authentication required + if (method === 'GET' && path === '/health') { + res.writeHead(200, { 'Content-Type': 'application/json' }); + return res.end(JSON.stringify({ + status: 'healthy', + timestamp: new Date().toISOString(), + provider: currentConfig.MODEL_PROVIDER + })); + } + + // Ignore count_tokens requests + if (path.includes('/count_tokens')) { + console.log(`[Server] Ignoring count_tokens request: ${path}`); + res.writeHead(200, { 'Content-Type': 'application/json' }); + return res.end(JSON.stringify({ + tokens: 0, + message: 'Token counting is not supported' + })); + } + // Allow overriding MODEL_PROVIDER via request header const modelProviderHeader = req.headers['model-provider']; if (modelProviderHeader) { @@ -566,9 +601,7 @@ function createRequestHandler(config) { console.log(`[Config] MODEL_PROVIDER overridden by header to: ${currentConfig.MODEL_PROVIDER}`); //delete req.headers['model-provider']; // 保持不变,以便后端可以继续处理原始头 } - - const requestUrl = new URL(req.url, `http://${req.headers.host}`); - let path = requestUrl.pathname; + // Check if the first path segment matches a MODEL_PROVIDER and switch if it does const pathSegments = path.split('/').filter(segment => segment.length > 0); if (pathSegments.length > 0) { @@ -605,39 +638,6 @@ function createRequestHandler(config) { return; } - const method = req.method; - if (method === 'OPTIONS') { - // 设置 CORS 头部,允许所有来源和方法 - res.setHeader('Access-Control-Allow-Origin', '*'); - res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); - res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-goog-api-key, Model-Provider'); // 添加 Model-Provider - - // OPTIONS 请求通常返回 204 No Content - res.writeHead(204); - res.end(); - return; - } - - // Health check endpoint - no authentication required - if (method === 'GET' && path === '/health') { - res.writeHead(200, { 'Content-Type': 'application/json' }); - return res.end(JSON.stringify({ - status: 'healthy', - timestamp: new Date().toISOString(), - provider: currentConfig.MODEL_PROVIDER - })); - } - - // Ignore count_tokens requests - if (path.includes('/count_tokens')) { - console.log(`[Server] Ignoring count_tokens request: ${path}`); - res.writeHead(200, { 'Content-Type': 'application/json' }); - return res.end(JSON.stringify({ - tokens: 0, - message: 'Token counting is not supported' - })); - } - if (!isAuthorized(req, requestUrl, currentConfig.REQUIRED_API_KEY)) { res.writeHead(401, { 'Content-Type': 'application/json' }); return res.end(JSON.stringify({ error: { message: 'Unauthorized: API key is invalid or missing.' } })); diff --git a/src/provider-pool-manager.js b/src/provider-pool-manager.js index f6260f5..8268fa6 100644 --- a/src/provider-pool-manager.js +++ b/src/provider-pool-manager.js @@ -117,7 +117,7 @@ export class ProviderPoolManager { * @param {string} providerType - The type of the provider. * @param {object} providerConfig - The configuration of the provider to mark. */ - markProviderHealthy(providerType, providerConfig) { + markProviderHealthy(isInit, providerType, providerConfig) { const pool = this.providerStatus[providerType]; if (pool) { const provider = pool.find(p => p.uuid === providerConfig.uuid); @@ -125,6 +125,9 @@ export class ProviderPoolManager { provider.config.isHealthy = true; provider.config.errorCount = 0; // Reset error count on health recovery provider.config.lastErrorTime = null; // Reset lastErrorTime when healthy + if (isInit) { + provider.config.usageCount = 0; // Reset usage count on health recovery + } console.log(`[ProviderPoolManager] Marked provider as healthy: ${JSON.stringify(providerConfig)} for type ${providerType}`); // 优化1: 使用防抖保存 @@ -137,7 +140,7 @@ export class ProviderPoolManager { * Performs health checks on all providers in the pool. * This method would typically be called periodically (e.g., via cron job). */ - async performHealthChecks() { + async performHealthChecks(isInit = false) { console.log('[ProviderPoolManager] Performing health checks on all providers...'); const now = new Date(); for (const providerType in this.providerStatus) { @@ -158,10 +161,11 @@ export class ProviderPoolManager { if (isHealthy) { if (!providerStatus.config.isHealthy) { // Provider was unhealthy but is now healthy - this.markProviderHealthy(providerType, providerConfig); + this.markProviderHealthy(isInit, providerType, providerConfig); console.log(`[ProviderPoolManager] Health check for ${JSON.stringify(providerConfig)} (${providerType}): Marked Healthy (actual check)`); } else { // Provider was already healthy and still is + this.markProviderHealthy(isInit, providerType, providerConfig); console.log(`[ProviderPoolManager] Health check for ${JSON.stringify(providerConfig)} (${providerType}): Still Healthy`); } } else {