背景痛点那些年我们一起踩过的毕设坑毕设季一到图书馆的插座永远不够用GitHub 的绿点也突然密集。可真正能把 Vue Node.js 跑通、顺利答辩的同学却不多。根据过去两年帮学弟学妹 Debug 的不完全统计最容易翻车的地方集中在下面三类全局状态滥用把用户信息、菜单权限、甚至当前分页数全塞进 Vuex结果一刷新页面全部归零调试时还得靠console.log大海捞针。SQL 注入风险后端直接拼接字符串写 SQLSELECT * FROM user WHERE id ${id}一交答辩老师一句“如果 id 是1 OR 11呢”直接社死。跨域配置错误前端axios.defaults.baseURL http://localhost:3000写死上线后忘记改结果一部署到服务器就 404连夜改代码心态炸裂。这些坑的本质是“课程思维”——代码跑通就行不考虑可读性、可维护性、可扩展性。下面就用一个“最小可用”但“工业级”的毕设模板带大家把思维切换到“工程化视角”。技术选型对比为什么不是 Egg/Nest Vue3 PostgreSQL技术选型没有银弹只有“适不适合当前阶段”。对毕设而言学习成本 社区资料 答辩老师认知才是最优解。下面给出一张“血泪对比表”帮你 5 分钟敲定方案。维度ExpressKoaEggNest学习曲线中文文档多多多少答辩老师认知高中低极低装饰代码量少少多巨多结论Express 语法与 Node.js 原生最接近老师一看就懂Koa 中间件洋葱模型虽优雅但解释成本高。Egg/Nest 的“企业级”反而成了答辩负担PASS。同理Vue2 资料多、选项式 API 与大部分教材同步Vue3 的 Composition API 虽香但老师一句“ref、reactive 是什么”就能把你问懵。数据库同理MySQL 关系模型 可视化工具Navicat让老师一眼看懂表结构MongoDB 的“灵活”在答辩时反而成了“字段随意”的把柄。最终锁定Express Vue2 MySQL前端用 Vue-CLI 一键脚手架后端自己搭成本最低、资料最稳。核心实现细节Clean Code 示范下面用“用户注册-登录-上传头像”这一黄金链路演示如何写出“老师挑不出毛病”的代码。所有文件均放在开源仓库graduation-vue-node根目录clone 即可跑。1. 项目骨架graduation-vue-node ├─ client/ // Vue2 前端 │ ├─ src/ │ │ ├─ api/ // API 请求层 │ │ ├─ router/ // 路由 │ │ └─ store/ // Vuex 模块化 ├─ server/ // Express 后端 │ ├─ controller/ // 业务逻辑 │ ├─ middleware/ // 错误处理、JWT、上传 │ ├─ models/ // Sequelize 模型 │ └─ routes/ // 路由 └─ upload/ // 静态资源头像2. 后端用户注册路由单一职责// server/routes/auth.js const express require(express); const bcrypt require(bcryptjs); const { User } require(../models); const { body, validationResult } require(express-validator); const router express.Router(); /** * POST /api/auth/register * 职责只做“数据校验 入库”不写业务规则 */ router.post( /register, [ body(username).isLength({ min: 3 }).trim().escape(), body(password).isLength({ min: 6 }), body(email).isEmail().normalizeEmail() ], async (req, res, next) { // 1. 校验 const errors validationResult(req); if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() }); // 2. 防重复 const { username, password, email } req.body; const exist await User.findOne({ where: { email } }); if (exist) return res.status(409).json({ msg: 邮箱已存在 }); // 3. 哈希 const hashed await bcrypt.hash(password, 10); // 4. 入库 const user await User.create({ username, email, password: hashed }); return res.json({ id: user.id, username, email }); } ); module.exports router;代码亮点用express-validator把“输入校验”从业务里剥出来单一职责。哈希强度 10兼顾安全与性能不在控制器写盐值。返回体剔除敏感字段password最小暴露原则。3. 前端Vuex 模块化封装// client/src/store/modules/user.js import { login, getInfo } from /api/user; const state { token: localStorage.getItem(token) || , name: , avatar: }; const mutations { SET_TOKEN: (state, token) { statetoken token; localStorage.setItem(token, token); }, CLEAR_TOKEN: (state) { state.token ; localStorage.removeItem(token); } }; const actions { // 登录 Login({ commit }, userInfo) { return new Promise((resolve, reject) { login(userInfo) .then(response { const { data } response; commit(SET_TOKEN, data.token); resolve(); }) .catch(error { reject(error); }); }); } }; export default { namespaced: true, state, mutations, actions };所有异步请求收拢到api/user.js组件只关心 dispatch。token双写state localStorage刷新不丢。命名空间开启避免模块冲突。4. 文件上传前后端联调后端用multer中间件限定大小与文件类型统一返回http://localhost:3000/upload/filename可访问地址前端用el-upload的before-upload钩子做二次校验直接回显头像。代码仓库已给出完整示例这里不再占篇幅。性能与安全让答辩老师闭嘴的 5 张底牌CORS 白名单生产环境不要把app.use(cors({ origin: * }))写死用.env注入白名单域名例如CORS_ORIGINhttps://grad.xxx.com。密码哈希 盐前文已用bcrypt但务必提醒老师“彩虹表”概念突出你对“暴力破解成本”的理解。输入校验双层保险前端vee-validate做用户体验后端express-validator做安全底线两者缺一不可。限流 防暴力用express-rate-limit对/api/auth/*做 15 分钟 5 次限制老师一听“接口安全”就点头。统一错误处理自定义errorHandler.js中间件把堆栈信息打印到logs/error.log却只对返回前端{ code, msg }不dump敏感信息。生产环境避坑指南从“能跑”到“上线”环境变量管理把JWT_SECRET、DB_PASS、CORS_ORIGIN全写进.env绝不提交到 Git。仓库只留.env.example做模板防止队友或自己覆盖配置。Git 忽略规则除了node_modules还要把upload/*、*.log、dist/写进.gitignore否则仓库体积爆炸CI 构建时间翻倍。Nginx 反向代理前端npm run build后生成静态文件放到/usr/share/nginx/html后端 3000 端口用pm2守护。Nginx 关键配置location /api/ { proxy_pass http://127.0.0.1:3000/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }一条命令sudo nginx -t检查通过再sudo nginx -s reload老师一看你懂运维印象分。自动部署用 GitHub Actions 监听main分支 pushCI 跑npm run test通过后 rsync 到云主机实现“写完即上线”。答辩现场可直接git push给老师看效果仪式感拉满。结语把课程项目变成可展示的作品集写完这篇笔记我最大的感受是——毕设不是终点而是 GitHub 首页最亮眼的 pinned repo。当你把 JWT、RESTful、CORS、Nginx 这些关键词串成一条完整链路再配一张架构图你的项目就已经超越“课程作业”成为可以拿去面试的作品集。所以fork 这份模板把你的业务逻辑替换进去记得写 README、画 ER 图、录一段 30 秒演示 GIF。下一次面试官问“你有全栈项目吗”你只需把链接甩过去然后静静看他点头。祝你毕设高分更祝你把这份代码变成未来工作的敲门砖。