feat: 地图闯关——知识岛地图+知识关问答页,对比度微调,SEO路由,v1.2.7
This commit is contained in:
+109
-105
@@ -1,105 +1,109 @@
|
||||
require('dotenv').config()
|
||||
|
||||
const express = require('express')
|
||||
const cors = require('cors')
|
||||
const helmet = require('helmet')
|
||||
const compression = require('compression')
|
||||
const morgan = require('morgan')
|
||||
const rateLimit = require('express-rate-limit')
|
||||
|
||||
const connectDB = require('./config/database')
|
||||
const initRoutes = require('./routes')
|
||||
const logger = require('./utils/logger')
|
||||
|
||||
// 创建 Express 应用
|
||||
const app = express()
|
||||
|
||||
// 数据库连接
|
||||
connectDB()
|
||||
|
||||
// 中间件配置
|
||||
app.use(helmet()) // 安全头部
|
||||
app.use(cors()) // 跨域支持
|
||||
app.use(compression()) // Gzip 压缩
|
||||
app.use(express.json({ limit: '10mb' })) // JSON 解析
|
||||
app.use(express.urlencoded({ extended: true, limit: '10mb' })) // URL 编码解析
|
||||
|
||||
// 日志中间件
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
app.use(morgan('dev'))
|
||||
} else {
|
||||
app.use(morgan('combined'))
|
||||
}
|
||||
|
||||
// 速率限制
|
||||
const limiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000, // 15 分钟
|
||||
max: 1000, // 每个 IP 最多 1000 次请求
|
||||
message: {
|
||||
success: false,
|
||||
error: '请求过于频繁,请稍后再试'
|
||||
}
|
||||
})
|
||||
app.use('/api/', limiter)
|
||||
|
||||
// 健康检查
|
||||
app.get('/health', (req, res) => {
|
||||
res.status(200).json({
|
||||
status: 'ok',
|
||||
timestamp: new Date().toISOString(),
|
||||
uptime: process.uptime()
|
||||
})
|
||||
})
|
||||
|
||||
// API 路由
|
||||
initRoutes(app)
|
||||
|
||||
// 404 处理
|
||||
app.use((req, res) => {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
error: '接口不存在',
|
||||
path: req.path
|
||||
})
|
||||
})
|
||||
|
||||
// 全局错误处理
|
||||
app.use((err, req, res, next) => {
|
||||
logger.error('服务器错误:', err)
|
||||
|
||||
res.status(err.status || 500).json({
|
||||
success: false,
|
||||
error: process.env.NODE_ENV === 'production'
|
||||
? '服务器内部错误'
|
||||
: err.message,
|
||||
stack: process.env.NODE_ENV === 'development' ? err.stack : undefined
|
||||
})
|
||||
})
|
||||
|
||||
// 启动服务器(仅在直接运行时启动,被测试 import 时不启动)
|
||||
const PORT = process.env.PORT || 3000
|
||||
let server = null
|
||||
|
||||
if (require.main === module) {
|
||||
server = app.listen(PORT, () => {
|
||||
logger.info(`🚀 服务器启动成功`)
|
||||
logger.info(`📍 端口: ${PORT}`)
|
||||
logger.info(`🌐 环境: ${process.env.NODE_ENV || 'development'}`)
|
||||
logger.info(`📊 健康检查: http://localhost:${PORT}/health`)
|
||||
})
|
||||
}
|
||||
|
||||
// 优雅关闭
|
||||
process.on('SIGTERM', () => {
|
||||
logger.info('📴 接收到 SIGTERM 信号,正在关闭服务器...')
|
||||
if (server) {
|
||||
server.close(() => {
|
||||
logger.info('✅ 服务器已关闭')
|
||||
process.exit(0)
|
||||
})
|
||||
} else {
|
||||
process.exit(0)
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = app
|
||||
require('dotenv').config()
|
||||
|
||||
const express = require('express')
|
||||
const cors = require('cors')
|
||||
const helmet = require('helmet')
|
||||
const compression = require('compression')
|
||||
const morgan = require('morgan')
|
||||
const rateLimit = require('express-rate-limit')
|
||||
|
||||
const connectDB = require('./config/database')
|
||||
const initRoutes = require('./routes')
|
||||
const seoRoutes = require('./routes/seo')
|
||||
const logger = require('./utils/logger')
|
||||
|
||||
// 创建 Express 应用
|
||||
const app = express()
|
||||
|
||||
// 数据库连接
|
||||
connectDB()
|
||||
|
||||
// SEO/GEO 路由(robots/sitemap/llms/about)
|
||||
app.use('/', seoRoutes)
|
||||
|
||||
// 中间件配置
|
||||
app.use(helmet()) // 安全头部
|
||||
app.use(cors()) // 跨域支持
|
||||
app.use(compression()) // Gzip 压缩
|
||||
app.use(express.json({ limit: '10mb' })) // JSON 解析
|
||||
app.use(express.urlencoded({ extended: true, limit: '10mb' })) // URL 编码解析
|
||||
|
||||
// 日志中间件
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
app.use(morgan('dev'))
|
||||
} else {
|
||||
app.use(morgan('combined'))
|
||||
}
|
||||
|
||||
// 速率限制
|
||||
const limiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000, // 15 分钟
|
||||
max: 1000, // 每个 IP 最多 1000 次请求
|
||||
message: {
|
||||
success: false,
|
||||
error: '请求过于频繁,请稍后再试'
|
||||
}
|
||||
})
|
||||
app.use('/api/', limiter)
|
||||
|
||||
// 健康检查
|
||||
app.get('/health', (req, res) => {
|
||||
res.status(200).json({
|
||||
status: 'ok',
|
||||
timestamp: new Date().toISOString(),
|
||||
uptime: process.uptime()
|
||||
})
|
||||
})
|
||||
|
||||
// API 路由
|
||||
initRoutes(app)
|
||||
|
||||
// 404 处理
|
||||
app.use((req, res) => {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
error: '接口不存在',
|
||||
path: req.path
|
||||
})
|
||||
})
|
||||
|
||||
// 全局错误处理
|
||||
app.use((err, req, res, next) => {
|
||||
logger.error('服务器错误:', err)
|
||||
|
||||
res.status(err.status || 500).json({
|
||||
success: false,
|
||||
error: process.env.NODE_ENV === 'production'
|
||||
? '服务器内部错误'
|
||||
: err.message,
|
||||
stack: process.env.NODE_ENV === 'development' ? err.stack : undefined
|
||||
})
|
||||
})
|
||||
|
||||
// 启动服务器(仅在直接运行时启动,被测试 import 时不启动)
|
||||
const PORT = process.env.PORT || 3000
|
||||
let server = null
|
||||
|
||||
if (require.main === module) {
|
||||
server = app.listen(PORT, () => {
|
||||
logger.info(`🚀 服务器启动成功`)
|
||||
logger.info(`📍 端口: ${PORT}`)
|
||||
logger.info(`🌐 环境: ${process.env.NODE_ENV || 'development'}`)
|
||||
logger.info(`📊 健康检查: http://localhost:${PORT}/health`)
|
||||
})
|
||||
}
|
||||
|
||||
// 优雅关闭
|
||||
process.on('SIGTERM', () => {
|
||||
logger.info('📴 接收到 SIGTERM 信号,正在关闭服务器...')
|
||||
if (server) {
|
||||
server.close(() => {
|
||||
logger.info('✅ 服务器已关闭')
|
||||
process.exit(0)
|
||||
})
|
||||
} else {
|
||||
process.exit(0)
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = app
|
||||
|
||||
Reference in New Issue
Block a user