server.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /**
  2. * Docker 镜像代理加速系统 - 服务器入口点
  3. */
  4. const express = require('express');
  5. const fs = require('fs').promises;
  6. const path = require('path');
  7. const bodyParser = require('body-parser');
  8. const session = require('express-session');
  9. const cors = require('cors');
  10. const http = require('http');
  11. const logger = require('./logger');
  12. const { ensureDirectoriesExist } = require('./init-dirs');
  13. const { downloadImages } = require('./download-images');
  14. const { gracefulShutdown } = require('./cleanup');
  15. const os = require('os');
  16. const { requireLogin } = require('./middleware/auth');
  17. const compatibilityLayer = require('./compatibility-layer');
  18. const initSystem = require('./scripts/init-system');
  19. // 设置日志级别 (默认INFO, 可通过环境变量设置)
  20. const logLevel = process.env.LOG_LEVEL || 'INFO';
  21. logger.setLogLevel(logLevel);
  22. logger.info(`日志级别已设置为: ${logLevel}`);
  23. // 导入配置
  24. const config = require('./config');
  25. // 导入中间件
  26. const { sessionActivity, sanitizeRequestBody, securityHeaders } = require('./middleware/auth');
  27. // 导入初始化调度器
  28. const { executeOnce } = require('./lib/initScheduler');
  29. // 初始化Express应用
  30. const app = express();
  31. const server = http.createServer(app);
  32. // 配置中间件
  33. app.use(cors());
  34. app.use(express.json());
  35. app.use(express.static('web'));
  36. app.use(bodyParser.urlencoded({ extended: true }));
  37. app.use(session({
  38. secret: config.sessionSecret || 'OhTq3faqSKoxbV%NJV',
  39. resave: true,
  40. saveUninitialized: true,
  41. cookie: {
  42. secure: config.secureSession || false,
  43. maxAge: 7 * 24 * 60 * 60 * 1000 // 7天(一周)
  44. }
  45. }));
  46. // 自定义中间件
  47. app.use(sessionActivity);
  48. app.use(sanitizeRequestBody);
  49. app.use(securityHeaders);
  50. // 请求日志中间件
  51. app.use((req, res, next) => {
  52. const start = Date.now();
  53. // 在响应完成后记录日志
  54. res.on('finish', () => {
  55. const duration = Date.now() - start;
  56. // 增强过滤条件
  57. const isSuccessfulGet = req.method === 'GET' && (res.statusCode === 200 || res.statusCode === 304);
  58. const isStaticResource = req.url.match(/\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$/i);
  59. const isCommonApiRequest = req.url.startsWith('/api/') &&
  60. (req.url.includes('/check-session') ||
  61. req.url.includes('/system-resources') ||
  62. req.url.includes('/docker/status'));
  63. const isErrorResponse = res.statusCode >= 400;
  64. // 只记录关键API请求和错误响应,过滤普通的API请求和静态资源
  65. if ((isErrorResponse ||
  66. (req.url.startsWith('/api/') && !isCommonApiRequest)) &&
  67. !isStaticResource &&
  68. !(isSuccessfulGet && isCommonApiRequest)) {
  69. // 记录简化的请求信息
  70. req.skipDetailedLogging = !isErrorResponse; // 非错误请求跳过详细日志
  71. logger.request(req, res, duration);
  72. }
  73. });
  74. next();
  75. });
  76. // 使用我们的路由注册函数加载所有路由
  77. logger.info('注册所有应用路由...');
  78. const registerRoutes = require('./routes');
  79. registerRoutes(app);
  80. // 提供兼容层以确保旧接口继续工作
  81. require('./compatibility-layer')(app);
  82. // 确保登录路由可用
  83. try {
  84. const loginRouter = require('./routes/login');
  85. app.use('/api', loginRouter);
  86. logger.success('✓ 已添加备用登录路由');
  87. } catch (loginError) {
  88. logger.error('无法加载备用登录路由:', loginError);
  89. }
  90. // 页面路由
  91. app.get('/', (req, res) => {
  92. res.sendFile(path.join(__dirname, 'web', 'index.html'));
  93. });
  94. app.get('/admin', (req, res) => {
  95. res.sendFile(path.join(__dirname, 'web', 'admin.html'));
  96. });
  97. app.get('/docs', (req, res) => {
  98. res.sendFile(path.join(__dirname, 'web', 'docs.html'));
  99. });
  100. // 废弃的登录页面路由 - 该路由未使用且导致404错误,现已移除
  101. // app.get('/login', (req, res) => {
  102. // // 检查用户是否已登录
  103. // if (req.session && req.session.user) {
  104. // return res.redirect('/admin'); // 已登录用户重定向到管理页面
  105. // }
  106. //
  107. // res.sendFile(path.join(__dirname, 'web', 'login.html'));
  108. // });
  109. // 404处理
  110. app.use((req, res) => {
  111. res.status(404).json({ error: '请求的资源不存在' });
  112. });
  113. // 错误处理中间件
  114. app.use((err, req, res, next) => {
  115. logger.error('应用错误:', err);
  116. res.status(500).json({ error: '服务器内部错误', details: err.message });
  117. });
  118. // 启动服务器
  119. const PORT = process.env.PORT || 3000;
  120. async function startServer() {
  121. server.listen(PORT, async () => {
  122. logger.info(`服务器已启动并监听端口 ${PORT}`);
  123. try {
  124. // 确保目录存在
  125. await ensureDirectoriesExist();
  126. logger.success('系统目录初始化完成');
  127. // 下载必要资源
  128. await downloadImages();
  129. logger.success('资源下载完成');
  130. // 初始化系统
  131. try {
  132. const { initialize } = require('./scripts/init-system');
  133. await initialize();
  134. logger.success('系统初始化完成');
  135. } catch (initError) {
  136. logger.warn('系统初始化遇到问题:', initError.message);
  137. logger.warn('某些功能可能无法正常工作');
  138. }
  139. // 尝试启动监控
  140. try {
  141. const monitoringService = require('./services/monitoringService');
  142. await monitoringService.startMonitoring();
  143. logger.success('监控服务已启动');
  144. } catch (monitoringError) {
  145. logger.warn('监控服务启动失败:', monitoringError.message);
  146. logger.warn('监控功能可能不可用');
  147. }
  148. // 尝试设置WebSocket
  149. try {
  150. const dockerRouter = require('./routes/docker');
  151. if (typeof dockerRouter.setupLogWebsocket === 'function') {
  152. dockerRouter.setupLogWebsocket(server);
  153. logger.success('WebSocket服务已启动');
  154. }
  155. } catch (wsError) {
  156. logger.warn('WebSocket服务启动失败:', wsError.message);
  157. logger.warn('容器日志实时流可能不可用');
  158. }
  159. logger.success('服务器初始化完成,系统已准备就绪');
  160. } catch (error) {
  161. logger.error('系统初始化失败,但服务仍将继续运行:', error);
  162. }
  163. });
  164. }
  165. startServer();
  166. // 处理进程终止信号
  167. process.on('SIGINT', gracefulShutdown);
  168. process.on('SIGTERM', gracefulShutdown);
  169. // 捕获未处理的Promise拒绝和未捕获的异常
  170. process.on('unhandledRejection', (reason, promise) => {
  171. logger.error('未处理的Promise拒绝:', reason);
  172. if (reason instanceof Error) {
  173. logger.debug('拒绝原因堆栈:', reason.stack);
  174. }
  175. });
  176. process.on('uncaughtException', (error) => {
  177. logger.error('未捕获的异常:', error);
  178. logger.error('错误堆栈:', error.stack);
  179. // 给日志一些时间写入后退出
  180. setTimeout(() => {
  181. logger.fatal('由于未捕获的异常,系统将在3秒后退出');
  182. setTimeout(() => process.exit(1), 3000);
  183. }, 1000);
  184. });
  185. // 导出服务器对象以供测试使用
  186. module.exports = server;