Files
jurong_Intermediate/server.js
2025-09-25 11:01:00 +08:00

153 lines
3.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 加载环境变量配置
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const path = require('path');
const rateLimit = require('express-rate-limit');
const { logger } = require('./config/logger');
const { errorHandler, notFound } = require('./middleware/errorHandler');
const fs = require('fs');
const app = express();
const PORT = process.env.PORT || 3000;
// 确保日志目录存在
const logDir = path.join(__dirname, 'logs');
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true });
}
// 中间件配置
// CORS配置 - 允许前端访问静态资源
app.use(cors({
origin: [
'http://localhost:5173',
'http://localhost:5176',
'http://localhost:5175',
'http://localhost:5174',
'http://localhost:3001',
'https://www.zrbjr.com',
'https://zrbjr.com'
],
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With']
}));
app.use(bodyParser.json({ limit: '10mb' }));
app.use(bodyParser.urlencoded({ extended: true, limit: '10mb' }));
// 请求日志中间件
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
// 只记录非正常状态码的请求日志过滤掉200、304等正常返回
if (res.statusCode >= 400 || res.statusCode < 200) {
logger.info('HTTP Request', {
method: req.method,
url: req.originalUrl,
statusCode: res.statusCode,
duration: `${duration}ms`,
ip: req.ip,
userAgent: req.get('User-Agent')
});
}
});
next();
});
// 限流中间件
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 1000, // 限制每个IP 15分钟内最多100个请求
message: {
success: false,
error: {
code: 'RATE_LIMIT_EXCEEDED',
message: '请求过于频繁,请稍后再试'
}
}
});
app.use('/', limiter);
// 引入数据库初始化模块
const { initDatabase } = require('./config/database-init');
// API路由
//用户相关
app.use('/auth', require('./routes/auth'));
//获取验证码
app.use('/captcha', require('./routes/captcha'));
//手机验证码
app.use('/sms', require('./routes/sms'));
//文件上传
app.use('/upload', require('./routes/upload'));
// 404处理
app.use(notFound);
// 全局错误处理中间件
app.use(errorHandler);
// 启动服务器
app.listen(PORT, async () => {
try {
logger.info('Server starting', { port: PORT });
console.log(`服务器运行在 http://localhost:${PORT}`);
await initDatabase();
global.captchaStore = new Map();
logger.info('Server started successfully', {
port: PORT,
environment: process.env.NODE_ENV || 'development'
});
} catch (error) {
logger.error('Failed to start server', { error: error.message });
process.exit(1);
}
});
// 优雅关闭
process.on('SIGTERM', async () => {
logger.info('SIGTERM received, shutting down gracefully');
try {
const { closeDB } = require('./database');
await closeDB();
} catch (error) {
logger.error('Error closing database', { error: error.message });
}
process.exit(0);
});
process.on('SIGINT', async () => {
logger.info('SIGINT received, shutting down gracefully');
try {
const { closeDB } = require('./database');
await closeDB();
} catch (error) {
logger.error('Error closing database', { error: error.message });
}
process.exit(0);
});
process.on('unhandledRejection', (reason, promise) => {
logger.error('Unhandled Rejection', { reason, promise });
});
process.on('uncaughtException', (error) => {
logger.error('Uncaught Exception', { error: error.message, stack: error.stack });
process.exit(1);
});