const express = require('express'); const cors = require('cors'); const bodyParser = require('body-parser'); const bcrypt = require('bcrypt'); const { body, validationResult } = require('express-validator'); const morgan = require('morgan'); const multer = require('multer'); const path = require('path'); const fs = require('fs'); // 创建 Express 应用实例 const app = express(); const PORT = 3000; // const uploadDir = path.join(__dirname, 'uploads'); // 使用中间件 app.use(cors({ origin: 'http://localhost:8080', // methods: ['GET', 'POST'], allowedHeaders: ['Content-Type'] })); app.use(express.json()); // 解析 JSON 格式的请求体 app.use(morgan('combined')); // 记录 HTTP 请求日志 // 请求限制 const limiter = require('express-rate-limit')({ windowMs: 15 * 60 * 1000, // 15 分钟 max: 100 // 每个 IP 限制 100 次请求 }); app.use(limiter); // 应用限制 // 检查并创建上传目录 if (!fs.existsSync(uploadDir)) { fs.mkdirSync(uploadDir, { recursive: true }); } // 设置文件存储配置 const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, uploadDir); }, filename: (req, file, cb) => { cb(null, Date.now() + path.extname(file.originalname)); } }); // 创建上传实例 const upload = multer({ storage, limits: { fileSize: 5 * 1024 * 1024 }, // 限制文件大小为 5MB fileFilter: (req, file, cb) => { const filetypes = /jpeg|jpg|png|gif|pdf/; const mimetype = filetypes.test(file.mimetype); const extname = filetypes.test(path.extname(file.originalname).toLowerCase()); if (mimetype && extname) { return cb(null, true); } cb(new Error('只允许上传 Excel文件')); } }); let users = []; // // 注册接口 app.post('/api/register', [ body('username').notEmpty().withMessage('用户名不能为空'), body('password').notEmpty().withMessage('密码不能为空'), body('confirm_password').custom((value, { req }) => { if (value !== req.body.password) { throw new Error('密码不匹配'); } return true; }) ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } const { username, password } = req.body; const existingUser = users.find(user => user.username === username); if (existingUser) { return res.status(400).send('用户名已被注册'); } const hashedPassword = await bcrypt.hash(password, 10); users.push({ username, password: hashedPassword }); res.status(201).send('注册成功'); }); // 登录接口 app.post('/api/login', [ body('username').isString().notEmpty(), body('password').isString().notEmpty() ], (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } const { username, password } = req.body; const user = users.find(u => u.username === username); if (user && bcrypt.compareSync(password, user.password)) { return res.status(200).json({ message: 'Login successful!' }); } else { return res.status(401).json({ message: 'Invalid username or password.' }); } }); // 获取数据接口 app.get('/api/data', (req, res) => { return res.status(200).json({ title: "欢迎使用系统", description: "这是一个模拟的系统,用于展示数据与交互" }); }); // 文件上传接口 app.post('/api/upload-file', upload.single('file'), (req, res) => { if (!req.file) { return res.status(400).json({ message: '没有文件上传' }); } res.status(200).json({ message: '文件上传成功', filename: req.file.filename }); }); // 提交成绩接口 app.post('/api/submit-grade', [ body('grade').isNumeric() ], (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } const { grade } = req.body; console.log(`Received grade: ${grade}`); return res.status(200).json({ message: 'Grade submitted successfully!', grade }); }); // 全局错误处理 app.use((err, req, res, next) => { console.error(err.stack); res.status(500).send('服务器内部错误'); }); // 启动服务器 app.listen(PORT, () => { console.log(`Server is running on http://localhost:8080`); });