const express = require('express'); const multer = require('multer'); const path = require('path'); const fs = require('fs'); const { v4: uuidv4 } = require('uuid'); const cors = require('cors'); const app = express(); const PORT = 30005; const BASE_URL = 'http://1.15.149.240'; // 启用 CORS app.use(cors()); app.use(express.json()); // 配置存储 const storage = multer.diskStorage({ destination: function (req, file, cb) { const model = req.body.model || 'default'; const date = new Date(); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); // 根据 model 确定存储路径 let modelPath = model; if (model === 'works' && file.mimetype.startsWith('video/')) { modelPath = 'video'; } const uploadDir = path.join('/data/uploads', modelPath, year, month, day); // 确保目录存在 try { fs.mkdirSync(uploadDir, { recursive: true }); console.log(`创建目录: ${uploadDir}`); } catch (err) { console.error(`创建目录失败: ${err.message}`); } cb(null, uploadDir); }, filename: function (req, file, cb) { const ext = path.extname(file.originalname); const filename = `${uuidv4()}${ext}`; cb(null, filename); } }); // 文件过滤器 const fileFilter = (req, file, cb) => { const allowedImageTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/bmp', 'image/webp']; const allowedVideoTypes = ['video/mp4', 'video/quicktime', 'video/x-msvideo', 'video/x-flv']; if (allowedImageTypes.includes(file.mimetype) || allowedVideoTypes.includes(file.mimetype)) { cb(null, true); } else { cb(new Error('不支持的文件类型'), false); } }; const upload = multer({ storage: storage, fileFilter: fileFilter, limits: { fileSize: 500 * 1024 * 1024 // 500MB } }); // 健康检查接口 app.get('/health', (req, res) => { res.json({ status: 'ok', message: '文件上传服务器运行正常', timestamp: new Date().toISOString() }); }); // 上传接口 app.post('/upload', upload.single('file'), (req, res) => { console.log('=== 收到上传请求 ==='); console.log('Body:', req.body); console.log('File:', req.file); if (!req.file) { console.error('没有上传文件'); return res.json({ status: 400, message: '没有上传文件' }); } const model = req.body.model || 'default'; const date = new Date(); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); // 根据文件类型确定路径 let modelPath = model; if (model === 'works' && req.file.mimetype.startsWith('video/')) { modelPath = 'video'; } const fileUrl = `${BASE_URL}/uploads/${modelPath}/${year}/${month}/${day}/${req.file.filename}`; console.log('文件上传成功:', fileUrl); console.log('=================='); res.json({ status: 200, message: '上传成功', data: { url: fileUrl, fileName: req.file.originalname, fileSize: req.file.size, mimeType: req.file.mimetype } }); }); // 错误处理 app.use((err, req, res, next) => { console.error('错误:', err.message); if (err instanceof multer.MulterError) { if (err.code === 'LIMIT_FILE_SIZE') { return res.json({ status: 400, message: '文件大小超过限制(最大 500MB)' }); } } res.json({ status: 500, message: err.message || '上传失败' }); }); // 静态文件服务 app.use('/uploads', express.static('/data/uploads')); app.listen(PORT, '0.0.0.0', () => { console.log('=========================================='); console.log(`文件上传服务器运行在端口 ${PORT}`); console.log(`上传接口: http://0.0.0.0:${PORT}/upload`); console.log(`健康检查: http://0.0.0.0:${PORT}/health`); console.log(`文件访问: ${BASE_URL}/uploads/`); console.log('=========================================='); });