博客系统架构与设计
2026年6月23日 blogTech 24 分钟阅读 7 次阅读
📖 文章摘要
详细的技术架构文档:系统设计、请求流程、数据库表结构、API 接口、前端页面路由、样式体系、目录结构。
Blog 项目架构与开发部署文档
blog.vue2.xyz — 个人博客系统
技术栈:Nuxt.js 3 (SSR) + FastAPI + SQLite
文档日期:2026-06-23
1. 项目概况
个人博客系统,支持文章发布、标签分类、评论审核、全文搜索、RSS 订阅、后台管理、临时网盘等功能。部署在韩国首尔服务器(<服务器IP>),与 MyChat 项目同机共存。
2. 技术栈
| 层级 | 技术 | 说明 |
|---|---|---|
| 前端框架 | Nuxt.js 3 (SSR) | Vue 3 全栈框架,服务端渲染支持 SEO |
| 样式 | Tailwind CSS | 响应式设计,参考 MapleBlog 毛玻璃质感 |
| 后端框架 | FastAPI (Python) | 类型安全,自动 Swagger 文档 |
| 数据库 | SQLite + SQLAlchemy | 单用户博客零运维成本 |
| WSGI 服务器 | Gunicorn + Uvicorn | 生产级 Python Web 服务 |
| 反向代理 | Nginx | HTTPS 卸载、静态文件直出、请求分发 |
| 进程管理 | systemd | blog-api、blog-web 各一个 service |
| 认证 | JWT (python-jose) | 无状态 token,7 天有效期 |
3. 系统架构
请求流程
用户 → blog.vue2.xyz:443
↓
Nginx (SSL 终止)
/ | \
/api/* /_nuxt/* /(其他页面)
| | |
FastAPI Nuxt SSR Nuxt SSR
:8001 :3000 :3000
| | |
SQLite 静态资源 FastAPI (SSR 时拉数据)
- 用户访问
https://blog.vue2.xyz/ - Nginx 443 端口接收,SSL 终止
- Nginx 路径分发:
/api/*→ 反向代理到 FastAPI (127.0.0.1:8001)/_nuxt/*→ 反向代理到 Nuxt SSR (127.0.0.1:3000) 的构建资源/uploads/*→ Nginx 直出静态文件(缓存 3 天)- 其余路径 → Nuxt.js SSR (127.0.0.1:3000)
- Nuxt SSR 阶段,需要数据的页面(如文章详情)内部请求 FastAPI API
- FastAPI 操作 SQLite 数据库,返回 JSON
- Nuxt 将数据嵌入完整 HTML,返回给浏览器/爬虫
端口映射
| 服务 | 端口 | 绑定地址 | 说明 |
|---|---|---|---|
| Nginx | 443/80 | 0.0.0.0 | HTTPS/HTTP,对外公开 |
| FastAPI | 8001 | 127.0.0.1 | 仅 Nginx 访问 |
| Nuxt SSR | 3000 | 127.0.0.1 | 仅 Nginx 访问 |
| SSH | 2894 | 0.0.0.0 | 非默认端口 |
4. 数据库设计
4.1 Article(文章)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | INT PK | 自增主键 |
| title | VARCHAR | 文章标题 |
| slug | VARCHAR UNIQUE | URL 标识 |
| content_md | TEXT | Markdown 原文 |
| content_html | TEXT | 缓存渲染后的 HTML |
| summary | VARCHAR | 摘要 |
| cover_image | VARCHAR | 封面图 URL |
| category_id | INT FK | 所属分类 |
| is_published | BOOL | 是否发布 |
| is_top | BOOL | 是否置顶 |
| allow_comment | BOOL | 允许评论 |
| meta | JSON | 扩展信息 |
| created_at | DATETIME | 创建时间 |
| updated_at | DATETIME | 更新时间 |
| published_at | DATETIME | 发布时间 |
4.2 Category(分类)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | INT PK | 自增主键 |
| name | VARCHAR | 名称 |
| slug | VARCHAR | URL 标识 |
| description | TEXT | 描述 |
| type | VARCHAR | 默认 'blog' |
4.3 Tag(标签)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | INT PK | 自增主键 |
| name | VARCHAR | 名称 |
| slug | VARCHAR | URL 标识 |
| type | VARCHAR | 默认 'blog' |
4.4 Comment(评论)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | INT PK | 自增主键 |
| article_id | INT FK | 所属文章 |
| parent_id | INT FK | 父评论(楼中楼预留) |
| author | VARCHAR | 昵称 |
| VARCHAR | 邮箱 | |
| content | TEXT | 评论内容 |
| is_approved | BOOL | 审核通过 |
| is_pinned | BOOL | 置顶 |
| created_at | DATETIME | 创建时间 |
4.5 Admin(管理员)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | INT PK | 自增主键 |
| username | VARCHAR | 用户名 |
| password_hash | VARCHAR | 密码哈希(SHA256) |
| nickname | VARCHAR | 显示名 |
| avatar | VARCHAR | 头像 URL |
4.6 SiteSetting(站点配置 key-value)
| 常用 key | 说明 |
|---|---|
| site_name | 站点名称 |
| author_name | 作者名 |
| author_avatar | 头像 base64 或 URL |
| author_tags | 技能标签 JSON 数组 |
| social_links | 社交链接 JSON 数组 |
| background_url | 背景图 URL |
| github_url / email | 旧版社交链接 |
4.7 Share(网盘文件)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | INT PK | 自增主键 |
| file_name | VARCHAR | 原始文件名 |
| file_path | VARCHAR | 服务器路径 |
| file_size | INT | 字节数 |
| password_hash | VARCHAR | 下载密码 SHA256 |
| password_plain | VARCHAR | 下载密码明文 |
| download_limit | INT | 下载限制(0=不限) |
| download_count | INT | 已下载次数 |
| expire_at | DATETIME | 过期时间 |
| created_at | DATETIME | 创建时间 |
4.8 DownloadLog(下载记录)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | INT PK | 自增主键 |
| share_id | INT FK | 所属文件 |
| downloaded_at | DATETIME | 下载时间 |
5. API 接口
公开接口
GET /api/articles 文章列表(分页,支持 ?page=&size=&category=&tag=)
GET /api/articles/{slug} 文章详情
GET /api/categories 分类列表
GET /api/tags 标签列表
GET /api/search?q=xxx 全文搜索
POST /api/comments 提交评论
GET /api/comments/{id} 评论列表
GET /api/feed/rss RSS 订阅
GET /api/site 站点信息(名称、头像、背景图等)
GET /api/sitemap.xml SEO sitemap
网盘接口
POST /api/pan/upload 上传(需管理员密码验证)
POST /api/pan/{id}/verify 验证下载密码,返回临时 token
GET /api/pan/{id}/download 下载文件(需 token,5min 有效)
GET /api/pan 文件列表(需 JWT)
GET /api/pan/{id}/logs 下载记录(需 JWT)
DELETE /api/pan/{id} 删除文件(需 JWT)
管理接口(需 JWT)
POST /api/auth/login 登录
POST /api/auth/change-password 修改密码
POST /api/admin/articles 创建文章
PUT /api/admin/articles/{id} 编辑文章
DELETE /api/admin/articles/{id} 删除
GET /api/admin/articles 列表(支持 ?q= 标题搜索)
PATCH /api/admin/articles/{id}/publish 发布/下架
POST /api/admin/categories 新增分类
DELETE /api/admin/categories/{id} 删除
POST /api/admin/tags 新增标签
DELETE /api/admin/tags/{id} 删除
GET /api/admin/comments 评论列表
POST /api/admin/comments/{id}/approve 审核通过
DELETE /api/admin/comments/{id} 删除
POST /api/admin/upload 上传图片(压缩 + quality 优化)
PUT /api/admin/site 更新站点配置
安全机制
- JWT 7 天有效期,存 cookie
- API 401 自动清除 cookie 跳转登录页
- 评论默认不显示,需后台审核通过
- 网盘双重验证:密码 → token(5min 窗口)→ 文件下载
- 密码 SHA256 存储
- 上传图片缩放 + quality 压缩
6. 前端页面
pages/
├── index.vue 首页(个人名片 + 文章瀑布流)
├── p/[slug].vue 文章详情(TOC + 分享 + 目录锚点)
├── categories.vue 分类列表
├── c/[slug].vue 分类文章列表(分页)
├── tags.vue 标签云
├── t/[slug].vue 标签文章列表(分页)
├── search.vue 搜索
├── about.vue 关于页
├── pan/
│ ├── index.vue 网盘上传(需管理员密码)
│ └── [id].vue 网盘下载(需密码验证)
└── admin/
├── login.vue 登录
├── index.vue 文章管理(搜索 + 列表)
├── edit/[id].vue 编辑器(分栏实时预览)
├── comments.vue 评论审核
├── pan.vue 网盘管理
├── settings.vue 站点设置(含修改密码)
├── categories.vue 分类管理
└── tags.vue 标签管理
核心组件
| 组件 | 作用 |
|---|---|
AppHeader.vue |
导航栏(桌面完整 + 移动端折叠菜单) |
BackButton.vue |
粘性返回按钮,根据路由名称显示对应标签 |
GlassCard.vue |
毛玻璃卡片容器 |
BackToTop.vue |
滚动 300px 后显示返回顶部按钮 |
ArticleCard.vue |
文章摘要卡片(整张可点击) |
ArticleMeta.vue |
文章元信息(日期、阅读量、标签) |
ContentRenderer.vue |
Markdown 转 HTML 渲染 |
TagBadge.vue |
标签徽章(循环配色) |
CommentSection.vue |
评论区 |
SearchBar.vue |
搜索输入框 |
ThemeToggle.vue |
主题切换(亮/暗/跟随系统) |
Pagination.vue |
分页导航(7 页截断模式) |
7. 样式体系
毛玻璃(Glassmorphism)
| 类名 | blur | 背景 | 用途 |
|---|---|---|---|
.glass |
20px | 18% 白 | 导航栏、主卡片 |
.glass-t |
10px | 10% 白 | 侧边栏、二级面板 |
.glass-l |
5px | 5% 白 | 标签、小元素 |
.glass-bare |
8px | 15% 白 | 浮动层 |
- 双 inset 高光 + 弹性缓动曲线
cubic-bezier(0.175, 0.885, 0.32, 2.2) - SVG 液态玻璃滤镜(
#glass-distortion):feTurbulence+feDisplacementMap - 渐变背景
#1a1a2e → #0d0d14,支持自定义背景图覆盖 - 文章卡片渐入动画(
stagger-fade-in),hover 悬停效果 - 标签循环配色:6 种低饱和颜色轮换(blue/emerald/violet/amber/rose/cyan),20% 不透明度
8. 目录结构
<项目路径>\
├── frontend/
│ ├── pages/ # 14 个页面
│ │ ├── pan/ # 网盘页面
│ │ └── admin/ # 后台管理
│ ├── components/
│ │ ├── base/ # 通用组件(AppHeader, BackButton 等)
│ │ ├── blog/ # 博客组件(ArticleCard, CommentSection 等)
│ │ ├── search/ # 搜索组件
│ │ └── admin/ # 后台组件
│ ├── composables/ # useApi, useAuth
│ ├── layouts/ # default.vue, admin.vue
│ ├── middleware/ # auth.ts 路由守卫
│ ├── assets/css/ # main.css(毛玻璃 + 组件样式)
│ ├── public/ # robots.txt 等静态文件
│ └── nuxt.config.ts
├── backend/
│ ├── main.py # FastAPI 入口 + CORS + 路由注册
│ ├── config.py # 配置(DB、JWT、上传路径)
│ ├── database.py # SQLAlchemy 引擎 + 会话管理
│ ├── models.py # 8 个 ORM 模型
│ ├── schemas.py # Pydantic 请求/响应模型
│ ├── auth.py # JWT 认证工具
│ ├── routers/
│ │ ├── articles.py # 公开文章接口
│ │ ├── categories.py # 公开分类接口
│ │ ├── tags.py # 公开标签接口
│ │ ├── comments.py # 公开评论接口
│ │ ├── search.py # 搜索接口
│ │ ├── feed.py # RSS 订阅
│ │ ├── site.py # 站点信息
│ │ ├── pan.py # 网盘
│ │ ├── sitemap.py # SEO
│ │ └── admin/ # 后台管理接口
│ ├── utils/markdown.py # Markdown 渲染工具
│ └── requirements.txt
├── data/ # 运行时数据(不提交 git)
│ ├── blog.db # SQLite 数据库
│ ├── uploads/ # 上传的图片
│ └── pan/ # 网盘文件
├── deploy/
│ ├── deploy.py # 一键部署工具
│ ├── sync-db.py # 数据库同步(旧版,建议用 deploy.py)
│ ├── blog-api.service # systemd 后端服务配置
│ ├── blog-web.service # systemd 前端 SSR 服务配置
│ └── nginx-blog.conf # Nginx 站点配置
├── docs/
│ └── architecture.md # 本文档
├── start.bat # 本地一键启动前后端
└── README.md
9. 本地开发
环境需求
- Python 3.11+
- Node.js 20+
- npm
方式一:一键启动
双击 start.bat,同时启动后端(:8001)和前端(:3000)。
方式二:分别启动
后端:
cd <项目路径>\backend
source venv/Scripts/activate
uvicorn main:app --reload --host 0.0.0.0 --port 8001
前端:
cd <项目路径>\frontend
npm install
npm run dev
访问 http://localhost:3000,后台 http://localhost:3000/admin
注意: 本地开发通过 Vite proxy 转接 /api 和 /uploads 到后端 8001 端口,无需 Nginx。
首次运行初始化
# 后端依赖
cd <项目路径>\backend
python -m venv venv
pip install -r requirements.txt
# 前端依赖
cd <项目路径>\frontend
npm install
10. 部署
详见 deploy.md — 包含服务器信息、首次部署、日常更新、数据库同步、服务器维护等完整流程。
快速部署
cd <项目路径>
python deploy/deploy.py
菜单选项:
- 1 - 完整部署:构建前端 → 打包前后端 → SCP 上传 → 服务器解压重启
- 2 - 数据库同步:下载(服务器→本地)/ 上传(本地→服务器)
11. 功能清单
前台
| 功能 | 说明 |
|---|---|
| 个人名片 | 毛玻璃卡片 + 头像 + 技能标签 + 社交图标 |
| 技能标签 | 后台可编辑,前台循环配色 |
| 社交图标 | 10+ 平台,后台管理增删 |
| 文章卡片 | 渐入动画 + 标签 + 蓝色边框悬停效果 |
| 文章目录 | 自动提取 h2-h4,锚点跳转带偏移补偿 |
| 返回顶部 | 滚动 300px 后出现 |
| 粘性返回按钮 | 根据路由显示对应上下文标签 |
| 毛玻璃质感 | SVG 液态滤镜 + 双 inset 高光 |
| 页面动画 | 淡入 + 上移入场 |
| 分页导航 | 7 页截断模式(1 ... n-1 n n+1 ... last) |
| SEO | Nuxt SSR + robots.txt + sitemap.xml |
| 临时网盘 | 上传/密码验证/token 下载 |
后台
| 功能 | 说明 |
|---|---|
| 文章搜索 | 标题模糊搜索 + 防抖 |
| Markdown 编辑器 | 分栏实时预览 |
| 文章状态 | 草稿 / 已发布 / 置顶 |
| 移动端适配 | 汉堡菜单 + 卡片式布局 |
| 评论审核 | 待审核 → 通过/删除 |
| 修改密码 | 需原密码验证 |
| 退出登录 | 清除 token + 跳转 |
| 401 自动跳转 | 全局 axios 拦截器 |
| 图片上传 | gif/jpg/png/webp,自动缩放 + quality 优化 |
| 站点配置 | 名称/头像/背景图/技能标签/社交链接 |
| 网盘管理 | 查看文件/下载记录/复制链接/删除 |
12. 踩坑记录
- bcrypt 版本:passlib 1.7.4 与 bcrypt 5.x 不兼容,需
pip install bcrypt==4.0.1 - Node.js 版本:Nuxt 3.13+ 需要 Node.js ≥ v20,Ubuntu apt 上的 v18 不够,需从 nodesource 安装
- SQLAlchemy cascade:自引用 Comment.replies 的
cascade="all, delete-orphan"会报错,去掉即可 - 相对导入:
from . import models在 uvicorn main:app 模式下失败,需用绝对导入import models - Windows 路径:SQLite URL 需要
.as_posix()转正斜杠 - 平台绑定依赖:npm install 在 Windows 上产生的 native binding,服务器上需
rm -rf node_modules package-lock.json后重新 install - Pydantic v2:NULL 值字段(如 summary=None)会被严格模式拒绝,schema 定义需设
= ""默认值 - Nginx body 大小:默认 1MB,上传图片需在 server 块加
client_max_body_size 20m - useAsyncData 分页:需要
{ watch: [page] }才能响应 query 变化重新 fetch - CSS animation-fill-mode:stagger 动画中的 transform 会覆盖 hover transform,两种效果不要混在同一个属性上
- Windows 文件锁:SQLite 被本地 dev server 占用时不能
os.remove,改用shutil.copy2覆盖写入 - scp 路径格式:Git Bash 下用 MSYS2 路径(
/d/Projects/...)或 cmd 格式(D:/...),不要混用
13. 后续规划
- 评论楼中楼(Comment.parent_id 已预留)
- 封面图管理(Article.cover_image 已预留,但编辑器未支持)
- Docker 化部署
- 数据库自动备份脚本
- 日志轮转配置
- 站点统计(PV/UV)
最后更新:2026年6月29日CC BY-NC-SA 4.0
评论
暂无评论,来写第一条吧
