news 2026/10/24 2:57:08

Flask+Vue博客系统设计与实现全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flask+Vue博客系统设计与实现全指南

先别急着把“博客系统”想得太简单,尤其是拿它当学业项目的朋友。一个能用来交作业、能写进简历、还能当面演示的系统,绝对不是“发文章、看文章”这么潦草。我这里分享一份基于 Flask + Vue 的博客系统设计与实现方案,从技术选型、数据表设计、核心接口,到前后端联调、部署避坑,一整套都拆开讲清楚。无论你是打算直接参考去做课设,还是想从零搭一个属于自己的博客项目,这篇内容都值得你花半小时读完。

我不喜欢绕弯子,咱们直接进入正题。

1. 项目设计与技术选型的核心思路

先聊设计思路。很多人一上来就开始写代码,结果写到一半发现表结构不合理、接口设计太乱,前后端对接的时候头皮发麻。这是典型的“没有先想清楚就动手”的坑。博客系统的核心是内容生产与消费,它不复杂,但需要你考虑到“谁在用、用来干什么、数据怎么流动”这三个问题。

1.1 为什么选 Flask + Vue 而不是其他组合

业界做博客系统,方案其实不少:Django 全家桶、Spring Boot + React、Express + Vue,甚至 PHP。但我个人认为,Flask + Vue 的搭配在国内学业场景里是最香的一组,原因有三。

第一,Flask 的轻量特性非常适合教学演示。Flask 不需要你像 Django 那样必须接受一套固定的大型框架约束,你可以自己控制 ORM、控制蓝图、控制装饰器,代码量清晰可见。导师问起来的时候,你也能很清楚地讲出“这段代码是干什么的”,这对于答辩来讲是很大的加分项。

第二,Vue 的渐进式特性降低了前端门槛。我见过不少同学学 React 学到 useState、useEffect、自定义 Hook 的时候直接放弃,但 Vue 的模板语法、计算属性、响应式数据这套心智模型,哪怕你只是刚刚搞懂 HTML + CSS + 简单 JS,靠着一套中文文档和组件化思维,也能把博客系统的后台管理页写得像模像样。

第三,前后端分离架构本身就是一个可以拿出来说的亮点。很多本科课设还在用 Flask 或者 Django 直接渲染 Jinja2 模板,虽然功能能做出来,但对于现在的评审标准来说,技术点明显落后了。用 Vue 做前端页面,用 Flask 只负责提供 JSON 数据接口,这中间涉及 RESTful API 风格、跨域处理、Token 认证、前后端分离部署,随便拎一条出来,都是答辩时能压住场子的词汇。

1.2 功能需求拆解

博客系统的功能,并不只是“写文章”和“看文章”这么简单。我们需要以“用户”的视角去拆,至少要拆出三类角色和一整套核心流程。

从普通访客角度看,他们需要看到博文列表、博文详情、根据分类或标签筛选内容、通过搜索找到历史文章。文字阅读体验要干净,页面加载要快,不需要登录就能浏览。

从博客作者角度看,他们需要登录后台、发文、编辑已有文章、管理文章状态(草稿还是发布),最好还要能看到文章的一些基础统计,比如浏览量。这里其实已经涉及到权限设计,不是所有注册用户都能发文章。

从系统管理员角度看,他们需要管理注册用户,可以禁用恶意账号、可以删除不合规的文章、可以维护分类和标签体系。这个身份在普通个人博客里可能不会单独分出来,但作为课设项目,你把它做出来了,系统层次感会立刻不一样。

核心流程则是:用户登录、鉴权、写文章、存草稿、发布、展示。我们把它映射到前后端交互中,就得到了一个完整的数据流闭环。

1.3 技术栈全景

再列一下完整的选型清单,方便你后面写文档或者做PPT的时候直接引用:

  • 后端:Flask 2.x + Python 3.8+
  • 数据库:MySQL 5.7+ 或 SQLite(开发阶段)
  • ORM:SQLAlchemy + Flask-SQLAlchemy 集成
  • 认证:JWT(JSON Web Token)
  • 密码加密:Werkzeug 自带的generate_password_hash/check_password_hash
  • 前端:Vue 3 + Vue Router + Pinia 或 Vuex
  • 前端 UI:Element Plus / 自己手写 CSS(看个人精力)
  • HTTP 客户端:Axios
  • 跨域处理:Flask-CORS

这套技术栈没有偏离主流,每一层都有成熟方案兜底。而且它有一个很大的好处:当你想扩展功能时,生态里几乎什么都有。

2. 数据库设计与后端接口规划

我一直认为数据库设计是整个项目成败的分水岭。如果一个博客系统的表结构乱到连自己都解释不清楚,那这个项目基本就废了一半。合理的表设计不仅能让前端拿数据变得很方便,还能让你的代码量少三分之一。

2.1 核心数据表结构

我做这类系统的时候,至少会设计五张核心表:用户表、文章表、分类表、标签表、文章标签关联表。这五张表已经能覆盖大多数场景,而且不会显得臃肿。

用户表(User),字段至少包括 id、username、password_hash、email、avatar(可选)、create_time、role。这里要特别提醒,密码字段千万不要存明文,即便只是课设项目也绝对不能。用 Werkzeug 提供的方法处理好哈希加密,这是一条安全红线。

文章表(Article),字段包括 id、title、content(长文本)、summary(摘要)、cover_image(封面图)、status(草稿/已发布)、view_count(浏览量)、category_id(外键)、author_id(外键)、create_time、update_time。这里 summary 很多人懒得填,我建议还是保留,因为它能让首页列表渲染更快,而且前端展示摘要信息也更美观。

分类表(Category)和标签表(Tag)比较简单,基本就是 id 和 name。但重点在它们与文章的关系:一篇文章只能属于一个分类,但可以打多个标签,所以需要一个中间表:post_tags,字段为 article_id 和 tag_id。

我见过很多新手做博客系统不建中间表,直接在文章表里存“tag1,tag2,tag3”这种逗号分隔字符串。当时看着方便,等你需要按某个标签检索所有文章时,就会发现自己掉进了 SQL LIKE 查询的大坑,效率低且逻辑混乱。中间表多花你两分钟时间,后面能省两小时。

2.2 RESTful API 路径规划

好的接口设计应该能做到“见名知意”,路径本身就是最好的注释。我个人习惯把前端需要的所有数据能力都规划成以下 RESTful API:

认证模块:

  • POST /api/auth/register:注册
  • POST /api/auth/login:登录
  • GET /api/auth/profile:获取当前登录用户信息

文章模块:

  • GET /api/articles:分页获取文章列表,支持 keyword、category_id、tag_id、page、page_size 查询参数
  • GET /api/articles/detail/ int:article_id :获取文章详情,同时浏览量加一
  • POST /api/articles/write:创建文章
  • PUT /api/articles/update/ int:article_id :编辑更新文章
  • DELETE /api/articles/delete/ int:article_id :删除文章

分类与标签:

  • GET /api/categories:所有分类
  • GET /api/tags:所有标签
  • GET /api/articles/tag/ int:tag_id :按标签查文章

后台管理:

  • GET /api/admin/users:用户列表(仅管理员)
  • PUT /api/admin/users/ int:user_id /status:禁用或启用用户

接口状态码也别乱用,统一规范:200 表示成功,201 表示资源创建成功,400 参数错误,401 未登录或 Token 失效,403 无权限,404 资源不存在,500 服务器内部错误。规范状态码会让前端逻辑判断变得异常轻松,这一点属于“成本极低但收益极高”的细节。

2.3 为什么要用 JWT 做认证

很多课设项目还在用 Session + Cookie,这在过去确实是主流,但放在前后端分离的场景下,JWT 几乎是唯一顺手的方案。

JWT 的核心思路是“无状态”。服务器不需要保存用户的登录会话信息,用户认证通过之后,服务器把用户 id、过期时间等信息通过私钥签发一段 Token 返回给前端。前端每次请求时在请求头里加上Authorization: Bearer <token>,后端接口通过装饰器验证 Token 是否合法,再从 Token 里取出用户信息。

Flask 里面实现 JWT 有两种常见路径:一是自己手写一个装饰器,用itsdangerous库生成和校验签名;二是直接用现成的flask-jwt-extended扩展。我个人的建议是,如果你是课设项目,最好自己手写一次简单的 JWT 签发与校验逻辑,代码量并不大,但当导师问你“Token 过期是怎么处理的”“如果客户端伪造 Token 怎么办”时,你能回答出里面涉及的签名算法和校验流程,这就是真实的项目含金量。用扩展一步到位,虽然省事,但答辩时很容易露怯。

3. Flask 后端实战:从蓝图到核心接口实现

接下来是动手环节。我不能只给你讲概念,咱们把核心代码逐个模块过一遍。整个 Flask 后端,我会按照模块化的思路来组织目录,这也是大项目的基本素养。

3.1 项目目录结构规划

不要把所有 Python 文件都堆在 app.py 一个文件里。如果项目代码少于 300 行,那随便写;可一旦涉及用户、文章、分类、标签、后台,你再堆一个文件,不仅自己维护困难,导师对代码质量的评分也会大打折扣。

我常用的目录结构如下:

project/ ├── app.py # Flask 入口 ├── config.py # 配置文件 ├── models/ │ ├── __init__.py │ ├── user.py │ ├── article.py │ ├── category.py │ └── tag.py ├── api/ │ ├── __init__.py │ ├── auth.py # 认证相关蓝图 │ ├── articles.py # 文章相关蓝图 │ ├── categories.py # 分类相关蓝图 │ └── admin.py # 后台管理蓝图 ├── utils/ │ ├── decorators.py # 统一返回装饰器 │ └── jwt_helper.py # JWT 工具函数 ├── requirements.txt └── run.py

前端项目放在独立目录,比如frontend/,两边完全分离,互不干扰。这个结构在心理上就暗示了一个事实:你的项目是标准的“前后端分离架构”,无论最后论文里写什么,代码结构本身已经证明了这一点。

3.2 统一返回格式与异常处理

博客接口如果东一个返回 JSON、西一个返回字符串,前端光处理返回结构就要写很多 if 分支。强烈建议一开始就统一返回格式。

我惯用的格式是:

{ "code": 200, "message": "success", "data": {} }

在 Flask 里可以定义统一的 APIResponse 工具函数,同时配合全局异常处理器。比如:

from flask import jsonify def success(data=None, message="success"): return jsonify({"code": 200, "message": message, "data": data}) def error(code=400, message="error"): return jsonify({"code": code, "message": message, "data": None}) @blueprint.app_errorhandler(404) def not_found(e): return error(404, "资源不存在")

这么写的好处是,前端在 Axios 拦截器里只判断返回体中的 code 字段即可,不需要每次都为“到底返回什么结构”发愁。真实开发中这种习惯叫“接口契约先行”,虽然听起来高大上,但它本质就是让前后端沟通成本降到最低。

3.3 核心文章接口实现

文章列表接口是最能体现“细节决定成败”的地方。它需要支持分页,还要支持多条件组合查询,并同时联查出分类名和作者昵称。

@bp.route("/articles", methods=["GET"]) def get_articles(): page = request.args.get("page", 1, type=int) per_page = request.args.get("page_size", 6, type=int) keyword = request.args.get("keyword", "", type=str) category_id = request.args.get("category_id", 0, type=int) query = Article.query.filter(Article.status == "published") if keyword: query = query.filter( db.or_(Article.title.contains(keyword), Article.summary.contains(keyword)) ) if category_id: query = query.filter(Article.category_id == category_id) pagination = query.order_by(Article.create_time.desc()).paginate( page=page, per_page=per_page, error_out=False ) result = [] for item in pagination.items: result.append({ "id": item.id, "title": item.title, "summary": item.summary, "cover_image": item.cover_image, "view_count": item.view_count, "category": item.category.name if item.category else "未分类", "author": item.author.username if item.author else "匿名", "create_time": item.create_time.strftime("%Y-%m-%d %H:%M"), "tags": [t.name for t in item.tags] }) return success({ "list": result, "total": pagination.total, "page": page, "pages": pagination.pages })

这段代码的核心在于 SQLAlchemy 的懒加载机制:当你访问item.category.name时,SQLAlchemy 会自动执行一条额外的查询去拿分类数据,数据量小没问题,一旦文章量大就会产生 N+1 查询问题。进阶做法是在查询时显式加上.options(joinedload(Article.category), joinedload(Article.tags)),但这属于性能优化范畴,课设做到这一步已经属于超纲亮点,你有精力可以写上,导师印象分会非常高。

文章详情接口我提一个容易忽略的点:浏览量 +1 操作应该是异步的,或者用一问一答两个接口。最简单可靠的做法是 GET 详情时同步自增一次。虽然官方统计不算精确,但演示效果完全够用。

@bp.route("/articles/detail/<int:aid>", methods=["GET"]) def article_detail(aid): article = Article.query.get_or_404(aid) article.view_count += 1 db.session.commit() return success({ "id": article.id, "title": article.title, "content": article.content, "create_time": article.create_time.strftime("%Y-%m-%d %H:%M"), "author": article.author.username if article.author else "匿名", "category": article.category.name if article.category else "未分类", "tags": [t.name for t in article.tags], "view_count": article.view_count })

3.4 JWT 认证装饰器的实践细节

写 JWT 装饰器,网上很多教程会给你一段看起来非常完美的代码,但里面总会埋着一个坑:装饰器内部直接固定获取用户名,可实际做前后端分离时,Token 里通常只存用户 id,你必须在请求进来时动态查库,或者至少在 Token 里保留当前用户的权限标识。

from functools import wraps from flask import request, jsonify from itsdangerous import TimedJSONWebSignatureSerializer as Serializer auth_s = Serializer("secret_key", expires_in=7200) def login_required(f): @wraps(f) def decorated(*args, **kwargs): token = request.headers.get("Authorization", "").replace("Bearer ", "") if not token: return jsonify({"code": 401, "message": "未登录"}), 401 try: data = auth_s.loads(token) except Exception: return jsonify({"code": 401, "message": "Token 无效或已过期"}), 401 current_user = User.query.get(data.get("uid")) if not current_user: return jsonify({"code": 401, "message": "用户不存在"}), 401 request.current_user = current_user return f(*args, **kwargs) return decorated

注意一个细节:请求头里Authorization的值很多前端会写成Bearer xxx格式,这是业界惯例,你在后端取出来时要把Bearer前缀去掉,否则拿去验签会失败。很多新手第一次对接就卡在这个看似不起眼的小坑上,排查半天。

4. Vue 前端实战:从脚手架到页面渲染

后端接口有了,前端就是把这些数据接过来,渲染成用户能看的界面。Vue 前端我依然会给出核心模块的实现思路,重点放在全流程打通上。

4.1 Vue 项目初始化与依赖安装

初始化推荐直接使用官方脚手架。如果你用的是 Vue 3,命令为:

npm create vite@latest frontend

进入项目之后,安装基础依赖:

npm install vue-router@4 axios element-plus

这里补充说一下 Element Plus。如果你的 UI 功底一般,直接用它准没错,表格、按钮、输入框、弹窗、表单校验全都有现成组件,能省出大量时间给你去调后端逻辑;如果你对 CSS 有点追求,也可以手写一套简洁风格,然后配一个自己设计的卡片式布局。两种方案我都做过,课设场景我更推荐 Element Plus,因为它的默认风格很“正经”,非常符合学业评审的审美取向。

4.2 Vue Router 与路由守卫

在博客前端,你至少要规划这些页面:首页(文章列表)、文章详情页、标签页、分类页、登录页、个人后台(发文、文章管理)。路由配置大致如下:

const routes = [ { path: "/", name: "home", component: HomeView }, { path: "/article/:id", name: "article-detail", component: ArticleDetail }, { path: "/login", name: "login", component: Login }, { path: "/dashboard", name: "dashboard", component: Dashboard, meta: { requiresAuth: true } }, ];

关键点在meta.requiresAuth的使用。在路由导航守卫里,判断用户当前是否登录,如果访问dashboard时不存在 Token,就强制跳回登录页:

router.beforeEach((to, from, next) => { if (to.meta.requiresAuth && !localStorage.getItem("token")) { next("/login"); } else { next(); } });

这个机制的底层语义是:单页面应用自己没有“服务器端会话”概念,一切都信任浏览器本地存储的 Token 状态。它对普通用户友好,也足够演示。学习这种写法的同时,你要理解它的局限:前端路由守卫拦截的只是页面入口,并不代表接口安全,真正安全校验始终是后端那层 JWT 装饰器。

4.3 Axios 封装与请求拦截

前端所有请求走 Axios,但不要每个页面都直接axios.get(),那样代码里会到处都是重复逻辑。正确思路是封装一个 request 实例,统一设置 baseURL,同时绑定请求拦截与响应拦截。

import axios from "axios"; import router from "../router"; const request = axios.create({ baseURL: "http://127.0.0.1:5000/api", timeout: 10000, }); request.interceptors.request.use((config) => { const token = localStorage.getItem("token"); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); request.interceptors.response.use( (response) => response.data, (error) => { if (error.response && error.response.status === 401) { localStorage.removeItem("token"); router.push("/login"); } return Promise.reject(error); } );

这个拦截器写完之后,你在任何组件里调用 API 都不需要再关心 Token 怎么加、状态码 401 怎么跳转这类重复劳动。把脏活集中到一处,是前端项目成熟的标志。

4.4 首页文章列表渲染与分页

首页要做的事情很简单,也很能体现系统性:调接口拿文章列表;根据分类、标签、关键字做筛选查询;点击卡片跳转详情页;底部分页组件控制页码。

使用 Element Plus 的el-pagination组件时,你要注意它给后端传参数的方式。一般我们会在 handlePageChange 方法里更新当前页码,然后重新请求数据:

const loadArticles = async (pageNum = 1) => { const params = { page: pageNum, page_size: 6, }; if (activeCategoryId.value) params.category_id = activeCategoryId.value; if (keyword.value) params.keyword = keyword.value; const res = await request.get("/articles", { params }); articleList.value = res.data.list; total.value = res.data.total; currentPage.value = res.data.page; };

这个函数要注意“筛选条件变化时,强制回到第一页”,否则你从第 5 页开始按分类筛选,很可能出现“当前页码超出总页数,列表空白”的 bug。一行代码解决:

watch([activeCategoryId, keyword], () => { loadArticles(1); });

这种细节,评审老师只要点了一下,你当场应对如流,就是毕业设计答辩里的超强加分段。

5. 前后端联调中的坑与排查技巧

项目做出来不难,但联调阶段才是最让新手崩溃的。我自己当初做类似项目时,也踩过不少坑,这里直接整理成速查表,希望你能少走弯路。

5.1 跨域问题

前后端分离架构下,前端运行在 5173 端口,后端跑在 5000 端口,浏览器会认为它们是两个来源,从而触发跨域限制。最稳妥的处理方式是后端启用 Flask-CORS。

pip install flask-cors

然后在 app.py 中初始化:

from flask_cors import CORS CORS(app, supports_credentials=True, origins=["http://localhost:5173"])

这里要注意origins参数,如果你把生产环境域名也写进去,那线上部署时会少很多麻烦;如果你不想限制,直接CORS(app)即可,但作为正式项目不推荐完全放开。

5.2 日期时间序列化问题

你在 Flask 的 JSON 返回中如果直接塞一个datetime对象,会得到类似"create_time": "Wed, 05 Oct 2022 14:23:00 GMT"的结果。前端要显示成漂亮格式,得额外 parse 一次。更省事的方法是在后端组装返回时统一用strftime转成字符串,像本文前面的示例代码那样。前端只负责展示,不负责转换,这会让你前端代码干净很多。

5.3 富文本内容渲染样式丢失

博客文章内容往往不是纯文本,而是 Markdown 格式或者 HTML 片段。前端在详情页渲染时,如果用v-html直接插入,默认标签没有基础样式,截图出来会非常难看。

解决办法是在前端引入一份 Markdown 样式表,或者是业界常用的markdown-it库,先解析成 HTML 再渲染:

npm install markdown-it

在文章详情组件中:

import MarkdownIt from "markdown-it"; const md = new MarkdownIt(); const renderContent = computed(() => md.render(article.value.content));

但要认清一点:富文本渲染和 XSS 防御是伴生问题。如果你把用户输入原样v-html渲染,恶意脚本也能被浏览器执行。课设项目可以不追求极致安全,但要自己在代码中感知这个问题。幸而markdown-it默认做了脚本标签转义,能手把手拦掉最危险的那部分。

5.4 浏览量与缓存问题

有些同学会发现,刷新页面后浏览量疯狂增加,这是因为每次刷新都重新加载资源并请求详情接口。合理做法是限定浏览量的增加频率,比如在 SessionStorage 里记录某一篇文章已经访问过,当日不再增加计数。

const VIEW_FLAG_KEY = "article_viewed_"; const increaseView = async (articleId) => { if (!sessionStorage.getItem(VIEW_FLAG_KEY + articleId)) { // 调用浏览接口 sessionStorage.setItem(VIEW_FLAG_KEY + articleId, "1"); } };

这种实现思路放在项目说明里讲出来,会给人一种你考虑过真实流量场景的感受,在“实用性”和“工程意识”两个维度的评价上,都会非常占优。

5.5 常见错误排查记录

如果你联调时遇到问题,先按下面这个清单自查一遍:

  • 前端网络请求 401:Token 丢失或过期,去 Application 面板看 LocalStorage 里面有没有值
  • 前端能拿到数据但页面空白:多半是字段名不匹配,后端返回的是create_time,前端取的是createTime,仔细对一下
  • 后端收到请求但拿不到参数:检查 Content-Type,POST 请求用 JSON 格式时记得设置Content-Type: application/json
  • 刷新页面变成 404:检查 Vue Router 的 history 模式配置,如果是部署到 Nginx,需要配置 try_files 重写规则,本地开发一般无碍
  • MySQL 连接报错:检查密码、端口、数据库名,以及用户授权问题

以上基本覆盖了 90% 的课设联调事故,剩下的都是查文档耐心就能解决的。

6. 文档编写与答辩演示的一些实在经验

很多同学代码写得挺不错,但最后交付的项目文档和答辩展示拉了胯,非常可惜。这里是常被忽视但能明显拉开差距的一些经验。

6.1 项目说明文档怎么组织

一份合格的学业项目文档至少要有这几个部分:项目背景与意义、需求分析、系统设计(含模块图或框架说明)、数据库设计、核心功能实现说明、测试分析、总结展望。

我建议在“需求分析”里就放一张用例表,把游客、作者、管理员三种角色的权限边界画清楚,这会非常直观。文档中贴代码时,只贴核心接口片段就好,不要整段 copy 进文档,否则老师大概率只翻目录不细读。

6.2 演示时最容易翻车的地方

演示视频或现场演示之前,请务必自己把整个流程从头到尾走三遍以上。最容易翻车的点有三个。

一是登录态失效。你上午写代码时 Token 有效期设的是 2 小时,下午演示时就过期了,一登录就报错,场面非常尴尬。建议演示前把 Token 有效期临时改成 24 小时,或者直接重新登录一次。

二是初始数据太难看。很多同学数据库里只有一条测试文章,点进去空空荡荡,视觉效果极差。建议提前造 10 篇以上的优质演示文章,内容长短不同、分类标签丰富、封面图齐全,演示时观感会好很多。文章内容最好和项目主题相关,比纯写“test”强百倍。

三是接口报错黑屏。演示过程中如果出现前端控制台红色报错,不要慌,第一时间看后端终端日志。最常见的两个问题:数据库被占用连不上、Token 过期。你提前预演过问题场景,现场应对就会从容得多。

6.3 如何把“普通项目”讲出高级感

同样是一个博客系统,有人答辩时轻描淡写,有人能讲出“架构设计、安全性设计、性能优化、部署方案”四条主线。区别就在于你对自己代码的理解深度。

我建议你在准备说明文档和答辩PPT时,至少准备以下几个问题的回答:

  • 为什么采用前后端分离,而不是服务端渲染?
  • 用户密码是怎么存储的?为什么不能存明文?
  • 如果访问量突然增大,后端哪些地方会成为瓶颈?
  • 文章搜索是怎么实现的?还有什么可优化的方向?

这三个问题,每一个都能展开讲三分钟。你把它们想明白了,答辩时压根不会怯场。

7. 部署发布:把它变成真正能访问的网站

本地跑通只是第一步。如果你想让项目能通过手机电脑随时访问,并把这件事写进项目成果里,那部署这一环必不可少。

7.1 构建前端静态资源

Vue 项目构建后得到 dist 目录,里面是纯静态文件。本地先执行:

npm run build

如果你在 config 或.env.production里没配好后端 API 地址,构建出的页面会默认请求http://localhost:5000/api,部署到线上必挂。这里要提前把 API 地址改成你服务器域名或 IP,比如http://123.45.67.89:5000/api。

7.2 常见部署方案

有两条路线,我简单说一下。

路线一:经典双进程。后端用 Gunicorn 启动 Flask 服务,监听 5000 端口;前端用 Nginx 托管 dist 目录,并将/api路径反向代理到http://127.0.0.1:5000。这是最正宗的前后端分离部署方式,工作量适中,性能也不差。

路线二:Vercel + 后端灵活部署,适合不想折腾服务器的人。前端构建后直接配给静态托管平台,但后端仍需找一台能长跑 Flask 的机器或容器平台。对课设来说路线一就够了,而且能讲清楚 Nginx 的作用。

7.3 上线前的安全检查

有些细节你本地开发不会注意,但一旦上了公网就会出问题:

  • 修改 Flask 的 SECRET_KEY,不要用代码里默认的"secret_key"这种弱口令
  • MySQL 数据库密码设置强密码,并创建独立业务账号,不要直接用 root
  • 关闭 Flask 的 debug 模式,否则线上报错会把完整堆栈暴露给访问者,这是极其危险的信息泄露
  • 对文章接口做最小限度的频率限制,防止有人借助公开接口恶意灌数据

这些建议听起来“重”,实际操作就是几行配置的事,却能让你在安全维度上甩开一大批同龄人。

8. 实际体验与项目心得

最后聊一点我个人的操作体会。博客系统作为学业设计选题,它最大的优势是“麻雀虽小,五脏俱全”。功能范围适中,但涉及的技术点密度很高,足够体现你的工程能力;同时它又是每个人都能理解的应用场景,演示时不需要额外解释“这个系统是干嘛的”,这能让你把宝贵时间花在展示设计思想和技术实现上,而不是向评审老师科普业务背景。

我在实际做这个项目时,最强烈的感受是“提前把接口约定好,整个开发进度会顺滑很多”。如果你是和另一位同学组队,一个写后端、一个写前端,那更要先花半天时间把 API 文档定下来,然后各写各的,后面联调时几乎不吵架。如果你是一个人独立完成,也建议先把所有接口路径和返回字段写在纸上,再分别填充前后端代码。这个“先契约、后实现”的工作习惯,值得带到未来任何项目中。

另外一个小建议:提交前记得把你的项目目录里可能藏着的虚拟环境、临时缓存文件、本地审美测试图片等一并清干净,保持压缩包整洁。导师下载你的项目后第一眼看到的,不是你写的核心代码有没有含金量,而是目录结构和文件命名有没有“乱”的气质。项目如人,第一印象很重要,整洁的项目结构本身就是加分项。

博客系统虽然经典,但它永远不会过时。每一天都有人需要表达、需要记录、需要被阅读,这些需求催生了无数博客系统版本。即使你今天交的是学业项目,这套对业务逻辑拆解、前后端协作、部署上线的理解,也会在你未来的真实工作中长时间复用。希望这篇内容能帮你把项目做得更扎实。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/24 2:56:30

GB32960-2025实时数据SM2验签原理与实现全解析

GB32960协议做过的同行应该都有体会——版本升级最怕的不是报文格式改动&#xff0c;而是安全机制重构。2025版协议里&#xff0c;实时数据上报链路强制加入SM2数字签名验签&#xff0c;这一刀切下来&#xff0c;很多之前只做了TCP透传、没碰过国密算法的团队直接在对接国家平台…

作者头像 李华
网站建设 2026/10/24 2:56:29

若依App版生命周期全解析:从Token到页面栈的实战指南

1. 若依App版本的“生命周期”到底在说什么如果你接触过若依&#xff08;RuoYi&#xff09;这个后台管理框架&#xff0c;应该知道它有很多个版本&#xff1a;单体版、前后端分离版、微服务版&#xff0c;还有一个专门面向移动端的RuoYiApp版。很多人第一次看到“生命周期”这三…

作者头像 李华
网站建设 2026/10/24 2:56:26

针尖电极击穿电压的COMSOL仿真:从电场到流注判据

“啪”的一声脆响&#xff0c;空气击穿时那道紫色电弧总能让人心头一紧。如果你在实验室对着一对针尖电极慢慢加压&#xff0c;电压表数字往上跳&#xff0c;空气却在某个瞬间突然从绝缘体变成导体&#xff0c;电流“啪”地窜过去——这就是击穿电压在起作用。很多人第一次接触…

作者头像 李华
网站建设 2026/10/24 2:55:56

FPU问题Python模拟:揭开确定性混沌与非线性热化的底层机制

简介&#xff1a;本资源是面向物理学与计算科学学习者的Fermi-Pasta-Ulam&#xff08;FPU&#xff09;非线性动力学问题Python模拟实现&#xff0c;适用于高年级本科生或研究生开展经典混沌、能量均分与非线性波传播等课题的数值实验。项目完整封装了含二次与三次非线性项的弹簧…

作者头像 李华
网站建设 2026/10/24 2:55:52

用NSGA2优化七次B样条:时间、能量、冲击三目标轨迹规划

做运动控制的人应该都有同感&#xff1a;轨迹规划是决定一台设备“上限”的东西&#xff0c;而大多数工程里真正卡脖子的不是轨迹算不出来&#xff0c;而是“算不出来真正好的轨迹”。我前阵子把一个直线搬运任务从三次B样条换成七次B样条&#xff0c;再把时间、能量、冲击三个…

作者头像 李华
网站建设 2026/10/24 2:55:30

libssh2 1.7.0全量集成包:VS/MinGW零链接错误实战指南

简介&#xff1a;本资源为 Windows 平台下基于 Visual Studio 2015 开发环境适配的 libssh2 1.7.0 官方库完整二进制分发包&#xff0c;面向 C/C 网络安全开发初学者及嵌入 SSH/SFTP 功能的桌面应用开发者。资源解决在 Win10 环境中快速集成 SSH 协议支持的核心依赖问题&#x…

作者头像 李华