234 lines
6.3 KiB
JavaScript
234 lines
6.3 KiB
JavaScript
/**
|
|
* 银行管理后台服务器
|
|
* @file server.js
|
|
* @description 银行系统后端API服务器主入口
|
|
*/
|
|
const express = require('express');
|
|
const http = require('http');
|
|
const cors = require('cors');
|
|
const dotenv = require('dotenv');
|
|
const helmet = require('helmet');
|
|
const compression = require('compression');
|
|
const swaggerUi = require('swagger-ui-express');
|
|
const swaggerSpec = require('./config/swagger');
|
|
const { sequelize } = require('./config/database');
|
|
const logger = require('./utils/logger');
|
|
const {
|
|
apiRateLimiter,
|
|
loginRateLimiter,
|
|
inputSanitizer,
|
|
sessionTimeoutCheck,
|
|
securityHeaders
|
|
} = require('./middleware/security');
|
|
|
|
// 加载环境变量
|
|
dotenv.config();
|
|
|
|
// 创建Express应用和HTTP服务器
|
|
const app = express();
|
|
const server = http.createServer(app);
|
|
const PORT = 5351; // 强制设置为5351端口
|
|
|
|
// 安全中间件
|
|
app.use(securityHeaders);
|
|
app.use(helmet());
|
|
app.use(compression());
|
|
|
|
// CORS配置
|
|
app.use(cors({
|
|
origin: process.env.CORS_ORIGIN || '*',
|
|
credentials: true,
|
|
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
|
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With']
|
|
}));
|
|
|
|
// 请求解析中间件
|
|
app.use(express.json({ limit: '10mb' }));
|
|
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
|
|
|
|
// 安全中间件
|
|
app.use(inputSanitizer);
|
|
app.use(apiRateLimiter);
|
|
|
|
// 静态文件服务
|
|
app.use('/uploads', express.static('uploads'));
|
|
|
|
// API文档
|
|
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
|
|
|
|
// 健康检查端点
|
|
app.get('/health', (req, res) => {
|
|
res.json({
|
|
success: true,
|
|
message: '银行系统运行正常',
|
|
timestamp: new Date().toISOString(),
|
|
version: '1.0.0'
|
|
});
|
|
});
|
|
|
|
// API路由
|
|
app.use('/api/auth', require('./routes/auth'));
|
|
app.use('/api/users', require('./routes/users'));
|
|
app.use('/api/accounts', require('./routes/accounts'));
|
|
app.use('/api/transactions', require('./routes/transactions'));
|
|
app.use('/api/dashboard', require('./routes/dashboard'));
|
|
app.use('/api/loan-products', require('./routes/loanProducts'));
|
|
app.use('/api/employees', require('./routes/employees'));
|
|
app.use('/api/projects', require('./routes/projects'));
|
|
app.use('/api/supervision-tasks', require('./routes/supervisionTasks'));
|
|
app.use('/api/installation-tasks', require('./routes/installationTasks'));
|
|
app.use('/api/completed-supervisions', require('./routes/completedSupervisions'));
|
|
app.use('/api/loan-applications', require('./routes/loanApplications'));
|
|
app.use('/api/loan-contracts', require('./routes/loanContracts'));
|
|
// app.use('/api/reports', require('./routes/reports'));
|
|
|
|
// 根路径
|
|
app.get('/', (req, res) => {
|
|
res.json({
|
|
success: true,
|
|
message: '银行管理后台API服务',
|
|
version: '1.0.0',
|
|
documentation: '/api-docs',
|
|
health: '/health'
|
|
});
|
|
});
|
|
|
|
// 404处理
|
|
app.use('*', (req, res) => {
|
|
res.status(404).json({
|
|
success: false,
|
|
message: '请求的资源不存在',
|
|
path: req.originalUrl
|
|
});
|
|
});
|
|
|
|
// 全局错误处理中间件
|
|
app.use((error, req, res, next) => {
|
|
logger.error('服务器错误:', error);
|
|
|
|
// 数据库连接错误
|
|
if (error.name === 'SequelizeConnectionError') {
|
|
return res.status(503).json({
|
|
success: false,
|
|
message: '数据库连接失败,请稍后重试'
|
|
});
|
|
}
|
|
|
|
// 数据库验证错误
|
|
if (error.name === 'SequelizeValidationError') {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: '数据验证失败',
|
|
errors: error.errors.map(err => ({
|
|
field: err.path,
|
|
message: err.message
|
|
}))
|
|
});
|
|
}
|
|
|
|
// 数据库唯一约束错误
|
|
if (error.name === 'SequelizeUniqueConstraintError') {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: '数据已存在,请检查输入'
|
|
});
|
|
}
|
|
|
|
// JWT错误
|
|
if (error.name === 'JsonWebTokenError') {
|
|
return res.status(401).json({
|
|
success: false,
|
|
message: '无效的访问令牌'
|
|
});
|
|
}
|
|
|
|
if (error.name === 'TokenExpiredError') {
|
|
return res.status(401).json({
|
|
success: false,
|
|
message: '访问令牌已过期'
|
|
});
|
|
}
|
|
|
|
// 默认错误响应
|
|
res.status(error.status || 500).json({
|
|
success: false,
|
|
message: process.env.NODE_ENV === 'production'
|
|
? '服务器内部错误'
|
|
: error.message,
|
|
...(process.env.NODE_ENV !== 'production' && { stack: error.stack })
|
|
});
|
|
});
|
|
|
|
// 优雅关闭处理
|
|
const gracefulShutdown = (signal) => {
|
|
logger.info(`收到 ${signal} 信号,开始优雅关闭...`);
|
|
|
|
server.close(async () => {
|
|
logger.info('HTTP服务器已关闭');
|
|
|
|
try {
|
|
await sequelize.close();
|
|
logger.info('数据库连接已关闭');
|
|
} catch (error) {
|
|
logger.error('关闭数据库连接时出错:', error);
|
|
}
|
|
|
|
logger.info('银行系统已安全关闭');
|
|
process.exit(0);
|
|
});
|
|
|
|
// 强制关闭超时
|
|
setTimeout(() => {
|
|
logger.error('强制关闭服务器');
|
|
process.exit(1);
|
|
}, 10000);
|
|
};
|
|
|
|
// 监听关闭信号
|
|
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
|
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
|
|
|
// 未捕获的异常处理
|
|
process.on('uncaughtException', (error) => {
|
|
logger.error('未捕获的异常:', error);
|
|
process.exit(1);
|
|
});
|
|
|
|
process.on('unhandledRejection', (reason, promise) => {
|
|
logger.error('未处理的Promise拒绝:', reason);
|
|
process.exit(1);
|
|
});
|
|
|
|
// 启动服务器
|
|
const startServer = async () => {
|
|
try {
|
|
// 测试数据库连接
|
|
await sequelize.authenticate();
|
|
logger.info('✅ 数据库连接成功');
|
|
|
|
// 同步数据库模型(开发环境)
|
|
// 按用户要求:不要初始化数据库(不自动建表/同步)
|
|
// if (process.env.NODE_ENV === 'development') {
|
|
// await sequelize.sync({ alter: true });
|
|
// logger.info('✅ 数据库模型同步完成');
|
|
// }
|
|
|
|
// 启动HTTP服务器
|
|
server.listen(PORT, () => {
|
|
logger.info(`🚀 银行管理后台服务器启动成功`);
|
|
logger.info(`📡 服务地址: http://localhost:${PORT}`);
|
|
logger.info(`📚 API文档: http://localhost:${PORT}/api-docs`);
|
|
logger.info(`🏥 健康检查: http://localhost:${PORT}/health`);
|
|
logger.info(`🌍 环境: ${process.env.NODE_ENV || 'development'}`);
|
|
});
|
|
|
|
} catch (error) {
|
|
logger.error('❌ 服务器启动失败:', error);
|
|
process.exit(1);
|
|
}
|
|
};
|
|
|
|
// 启动服务器
|
|
startServer();
|
|
|
|
module.exports = app; |