llm-chat/backend/app.js

256 lines
6.2 KiB
JavaScript
Raw Normal View History

const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const compression = require('compression');
const dotenv = require('dotenv');
// 导入中间件
const { requestLogger, consoleLogger, errorLogger, apiStats } = require('./middleware/logger');
const { notFoundHandler, globalErrorHandler, gracefulShutdown } = require('./middleware/errorHandler');
const { globalRateLimit, chatRateLimit } = require('./middleware/rateLimit');
const { sessionAuth, contentTypeCheck } = require('./middleware/auth');
// 导入路由
const apiRoutes = require('./routes');
// 导入数据库
const database = require('./models/database');
// 导入配置验证
const { validateConfig } = require('./config/llm');
// 加载环境变量
dotenv.config();
class App {
constructor() {
this.app = express();
this.port = process.env.PORT || 3000;
this.env = process.env.NODE_ENV || 'development';
// 初始化应用
this.initializeMiddlewares();
this.initializeRoutes();
this.initializeErrorHandling();
this.initializeGracefulShutdown();
}
/**
* 初始化中间件
*/
initializeMiddlewares() {
// 安全相关中间件
this.app.use(helmet({
contentSecurityPolicy: false, // 禁用CSP以避免开发时的问题
crossOriginEmbedderPolicy: false
}));
// 启用 trust proxy用于正确获取客户端IP
this.app.set('trust proxy', 1);
// CORS配置
const corsOptions = {
origin: process.env.CORS_ORIGIN?.split(',') || ['http://localhost:5173'],
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'x-api-key', 'x-session-id']
};
this.app.use(cors(corsOptions));
// 压缩响应
this.app.use(compression());
// 解析JSON请求体
this.app.use(express.json({
limit: '10mb',
strict: true
}));
// 解析URL编码的请求体
this.app.use(express.urlencoded({
extended: true,
limit: '10mb'
}));
// 日志中间件
this.app.use(consoleLogger);
this.app.use(requestLogger);
this.app.use(errorLogger);
// API统计中间件
this.app.use(apiStats);
// 会话认证中间件
this.app.use(sessionAuth);
// 内容类型检查中间件
this.app.use('/api', contentTypeCheck());
// 全局速率限制
this.app.use('/api', globalRateLimit);
// 聊天API专用速率限制
this.app.use('/api/chat', chatRateLimit);
}
/**
* 初始化路由
*/
initializeRoutes() {
// 根路径
this.app.get('/', (req, res) => {
res.json({
success: true,
data: {
name: 'LLM Chat Website Backend',
version: '1.0.0',
environment: this.env,
timestamp: new Date().toISOString()
},
message: '欢迎使用大语言模型聊天网站后端服务'
});
});
// API路由
this.app.use('/api', apiRoutes);
// 静态文件服务(如果需要)
this.app.use('/static', express.static('public'));
}
/**
* 初始化错误处理
*/
initializeErrorHandling() {
// 404处理
this.app.use(notFoundHandler);
// 全局错误处理
this.app.use(globalErrorHandler);
}
/**
* 初始化优雅关闭
*/
initializeGracefulShutdown() {
gracefulShutdown();
}
/**
* 初始化数据库
*/
async initializeDatabase() {
try {
await database.initialize();
console.log('数据库初始化完成');
return true;
} catch (error) {
console.error('数据库初始化失败:', error);
return false;
}
}
/**
* 验证配置
*/
validateConfiguration() {
console.log('验证配置...');
// 验证LLM配置
const llmConfigValid = validateConfig();
if (!llmConfigValid) {
console.warn('LLM配置可能不完整请检查环境变量');
}
// 验证必要的环境变量
const requiredEnvVars = ['PORT'];
const missingEnvVars = requiredEnvVars.filter(envVar => !process.env[envVar]);
if (missingEnvVars.length > 0) {
console.warn('缺少环境变量:', missingEnvVars.join(', '));
}
console.log('配置验证完成');
return true;
}
/**
* 启动服务器
*/
async start() {
try {
console.log('启动应用程序...');
// 验证配置
this.validateConfiguration();
// 初始化数据库
const dbInitialized = await this.initializeDatabase();
if (!dbInitialized) {
throw new Error('数据库初始化失败');
}
// 启动HTTP服务器
const server = this.app.listen(this.port, () => {
console.log(`
🚀 服务器启动成功
📝 环境: ${this.env}
🌐 端口: ${this.port}
🔗 本地地址: http://localhost:${this.port}
📊 API文档: http://localhost:${this.port}/api
🏥 健康检查: http://localhost:${this.port}/api/health
`);
});
// 设置服务器超时
server.timeout = 30000; // 30秒
// 处理服务器错误
server.on('error', (error) => {
if (error.code === 'EADDRINUSE') {
console.error(`❌ 端口 ${this.port} 已被占用`);
process.exit(1);
} else {
console.error('❌ 服务器启动失败:', error);
process.exit(1);
}
});
// 优雅关闭处理
const gracefulShutdown = () => {
console.log('📝 正在关闭服务器...');
server.close(async () => {
console.log('🔒 HTTP服务器已关闭');
try {
await database.close();
console.log('🔒 数据库连接已关闭');
} catch (error) {
console.error('关闭数据库连接失败:', error);
}
console.log('👋 应用程序已安全退出');
process.exit(0);
});
};
process.on('SIGTERM', gracefulShutdown);
process.on('SIGINT', gracefulShutdown);
return server;
} catch (error) {
console.error('❌ 应用程序启动失败:', error);
process.exit(1);
}
}
/**
* 获取Express应用实例
*/
getApp() {
return this.app;
}
}
module.exports = App;