anti_api / src /server /index.js
liuw15's picture
为gemini端口加上验证
e61044b
/**
* 服务器主入口
* Express 应用配置、中间件、路由挂载、服务器启动和关闭
*/
import express from 'express';
import cors from 'cors';
import path from 'path';
import { closeRequester } from '../api/client.js';
import logger from '../utils/logger.js';
import config from '../config/config.js';
import memoryManager from '../utils/memoryManager.js';
import { getPublicDir, getRelativePath } from '../utils/paths.js';
import { MEMORY_CHECK_INTERVAL } from '../constants/index.js';
import { errorHandler } from '../utils/errors.js';
import { getChunkPoolSize, clearChunkPool } from './stream.js';
// 路由模块
import adminRouter from '../routes/admin.js';
import sdRouter from '../routes/sd.js';
import openaiRouter from '../routes/openai.js';
import geminiRouter from '../routes/gemini.js';
import claudeRouter from '../routes/claude.js';
const publicDir = getPublicDir();
logger.info(`静态文件目录: ${getRelativePath(publicDir)}`);
const app = express();
// ==================== 内存管理 ====================
memoryManager.setThreshold(config.server.memoryThreshold);
memoryManager.start(MEMORY_CHECK_INTERVAL);
// ==================== 基础中间件 ====================
app.use(cors());
app.use(express.json({ limit: config.security.maxRequestSize }));
// 静态文件服务
app.use('/images', express.static(path.join(publicDir, 'images')));
app.use(express.static(publicDir));
// 管理路由
app.use('/admin', adminRouter);
// 使用统一错误处理中间件
app.use(errorHandler);
// ==================== 请求日志中间件 ====================
app.use((req, res, next) => {
const ignorePaths = [
'/images', '/favicon.ico', '/.well-known',
'/sdapi/v1/options', '/sdapi/v1/samplers', '/sdapi/v1/schedulers',
'/sdapi/v1/upscalers', '/sdapi/v1/latent-upscale-modes',
'/sdapi/v1/sd-vae', '/sdapi/v1/sd-modules'
];
// 提前获取完整路径,避免在路由处理后 req.path 被修改为相对路径
const fullPath = req.originalUrl.split('?')[0];
if (!ignorePaths.some(p => fullPath.startsWith(p))) {
const start = Date.now();
res.on('finish', () => {
logger.request(req.method, fullPath, res.statusCode, Date.now() - start);
});
}
next();
});
// SD API 路由
app.use('/sdapi/v1', sdRouter);
// ==================== API Key 验证中间件 ====================
app.use((req, res, next) => {
if (req.path.startsWith('/v1/')) {
const apiKey = config.security?.apiKey;
if (apiKey) {
const authHeader = req.headers.authorization || req.headers['x-api-key'];
const providedKey = authHeader?.startsWith('Bearer ') ? authHeader.slice(7) : authHeader;
if (providedKey !== apiKey) {
logger.warn(`API Key 验证失败: ${req.method} ${req.path} (提供的Key: ${providedKey ? providedKey.substring(0, 10) + '...' : '无'})`);
return res.status(401).json({ error: 'Invalid API Key' });
}
}
} else if (req.path.startsWith('/v1beta/')) {
const apiKey = config.security?.apiKey;
if (apiKey) {
const providedKey = req.query.key || req.headers['x-goog-api-key'];
if (providedKey !== apiKey) {
logger.warn(`API Key 验证失败: ${req.method} ${req.path} (提供的Key: ${providedKey ? providedKey.substring(0, 10) + '...' : '无'})`);
return res.status(401).json({ error: 'Invalid API Key' });
}
}
}
next();
});
// ==================== API 路由 ====================
// OpenAI 兼容 API
app.use('/v1', openaiRouter);
// Gemini 兼容 API
app.use('/v1beta', geminiRouter);
// Claude 兼容 API(/v1/messages 由 claudeRouter 处理)
app.use('/v1', claudeRouter);
// ==================== 系统端点 ====================
// 内存监控端点
app.get('/v1/memory', (req, res) => {
const usage = process.memoryUsage();
res.json({
heapUsed: usage.heapUsed,
heapTotal: usage.heapTotal,
rss: usage.rss,
external: usage.external,
arrayBuffers: usage.arrayBuffers,
pressure: memoryManager.getCurrentPressure(),
poolSizes: memoryManager.getPoolSizes(),
chunkPoolSize: getChunkPoolSize()
});
});
// 健康检查端点
app.get('/health', (req, res) => {
res.json({ status: 'ok', uptime: process.uptime() });
});
// ==================== 服务器启动 ====================
const server = app.listen(config.server.port, config.server.host, () => {
logger.info(`服务器已启动: ${config.server.host}:${config.server.port}`);
});
server.on('error', (error) => {
if (error.code === 'EADDRINUSE') {
logger.error(`端口 ${config.server.port} 已被占用`);
process.exit(1);
} else if (error.code === 'EACCES') {
logger.error(`端口 ${config.server.port} 无权限访问`);
process.exit(1);
} else {
logger.error('服务器启动失败:', error.message);
process.exit(1);
}
});
// ==================== 优雅关闭 ====================
const shutdown = () => {
logger.info('正在关闭服务器...');
// 停止内存管理器
memoryManager.stop();
logger.info('已停止内存管理器');
// 关闭子进程请求器
closeRequester();
logger.info('已关闭子进程请求器');
// 清理对象池
clearChunkPool();
logger.info('已清理对象池');
server.close(() => {
logger.info('服务器已关闭');
process.exit(0);
});
// 5秒超时强制退出
setTimeout(() => {
logger.warn('服务器关闭超时,强制退出');
process.exit(0);
}, 5000);
};
process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);
// ==================== 异常处理 ====================
process.on('uncaughtException', (error) => {
logger.error('未捕获异常:', error.message);
// 不立即退出,让当前请求完成
});
process.on('unhandledRejection', (reason, promise) => {
logger.error('未处理的 Promise 拒绝:', reason);
});