const express = require('express'); const cors = require('cors'); const helmet = require('helmet'); const dotenv = require('dotenv'); const rateLimit = require('express-rate-limit'); // 加载环境变量 dotenv.config(); // 创建Express应用 const app = express(); const PORT = process.env.PORT || 3350; // 生产环境使用3350端口 // 中间件 app.use(helmet()); // 安全头部 app.use(cors()); // 跨域支持 app.use(express.json({ limit: '10mb' })); // JSON解析 app.use(express.urlencoded({ extended: true, limit: '10mb' })); // URL编码解析 // 速率限制 const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15分钟 max: 1000, // 生产环境提高限制 message: '请求过于频繁,请稍后再试' }); app.use(limiter); // 基础路由 app.get('/', (req, res) => { res.json({ message: '欢迎使用锡林郭勒盟地区智慧养殖产业平台API服务', version: '1.0.0', environment: process.env.NODE_ENV || 'development', timestamp: new Date().toISOString(), docs: 'https://xlapi.jiebanke.com/docs' }); }); app.get('/health', (req, res) => { res.json({ status: 'OK', timestamp: new Date().toISOString(), uptime: process.uptime(), memory: process.memoryUsage() }); }); // API信息端点 app.get('/api/info', (req, res) => { res.json({ name: 'xlxumu-api', version: '1.0.0', environment: process.env.NODE_ENV, port: PORT, node_version: process.version, platform: process.platform }); }); // 大屏可视化地图数据接口 app.get('/api/v1/dashboard/map/regions', (req, res) => { // 模拟锡林郭勒盟各区域数据 const regions = [ { id: 'xlg', name: '锡林浩特市', coordinates: [116.093, 43.946], cattle_count: 25600, farm_count: 120, output_value: 650000000 }, { id: 'dwq', name: '东乌旗', coordinates: [116.980, 45.514], cattle_count: 18500, farm_count: 95, output_value: 480000000 }, { id: 'xwq', name: '西乌旗', coordinates: [117.615, 44.587], cattle_count: 21200, farm_count: 108, output_value: 520000000 }, { id: 'abg', name: '阿巴嘎旗', coordinates: [114.971, 44.022], cattle_count: 16800, farm_count: 86, output_value: 420000000 }, { id: 'snz', name: '苏尼特左旗', coordinates: [113.653, 43.859], cattle_count: 12400, farm_count: 65, output_value: 310000000 } ]; res.json({ regions }); }); app.get('/api/v1/dashboard/map/region/:regionId', (req, res) => { const { regionId } = req.params; // 模拟各区域详细数据 const regionDetails = { 'xlg': { region: { id: 'xlg', name: '锡林浩特市', coordinates: [116.093, 43.946], cattle_count: 25600, farm_count: 120, output_value: 650000000, trend: 'up' }, farms: [ { id: 'FARM001', name: '锡林浩特市第一牧场', coordinates: [116.120, 43.950], cattle_count: 2450, output_value: 62000000 }, { id: 'FARM002', name: '锡林浩特市第二牧场', coordinates: [116.080, 43.930], cattle_count: 2100, output_value: 53000000 } ] }, 'dwq': { region: { id: 'dwq', name: '东乌旗', coordinates: [116.980, 45.514], cattle_count: 18500, farm_count: 95, output_value: 480000000, trend: 'up' }, farms: [ { id: 'FARM003', name: '东乌旗牧场A', coordinates: [116.990, 45.520], cattle_count: 1950, output_value: 49000000 } ] } }; const detail = regionDetails[regionId]; if (detail) { res.json(detail); } else { res.status(404).json({ error: '区域未找到' }); } }); // 错误处理中间件 app.use((err, req, res, next) => { console.error('服务器错误:', err.stack); res.status(500).json({ error: '内部服务器错误', message: process.env.NODE_ENV === 'development' ? err.message : 'Something went wrong!' }); }); // 404处理 app.use((req, res) => { res.status(404).json({ error: '接口未找到', path: req.path, method: req.method }); }); // 优雅关机处理 process.on('SIGINT', () => { console.log('\n收到SIGINT信号,正在优雅关闭服务器...'); process.exit(0); }); process.on('SIGTERM', () => { console.log('\n收到SIGTERM信号,正在优雅关闭服务器...'); process.exit(0); }); // 启动服务器 const server = app.listen(PORT, '0.0.0.0', () => { console.log(`🚀 API服务器正在运行:`); console.log(` 📍 本地: http://localhost:${PORT}`); console.log(` 🌐 网络: http://0.0.0.0:${PORT}`); console.log(` 🏷️ 环境: ${process.env.NODE_ENV || 'development'}`); console.log(` ⏰ 启动时间: ${new Date().toLocaleString()}`); }); // 设置超时 server.timeout = 60000; server.keepAliveTimeout = 5000; module.exports = app;