一个功能完善的前后端分离个人博客系统,采用 Vue 3 + Express + MongoDB 技术栈开发,支持实时聊天、社交互动、文章管理等功能。
- Markdown 编辑器:完整的 Markdown 语法支持,实时预览,代码高亮,图片/视频上传
- MD文件导入:支持导入 .md、.markdown、.txt 文件,自动提取标题
- 文章管理:支持文章的发布、编辑、删除、草稿保存,文章标签和分类管理
- 文章互动:点赞、收藏、评论功能
- 文章审核:管理员审核机制,支持通过/拒绝
- 评论功能:支持评论的发布、回复、删除
- 评论审核:被举报多次的评论进入审核流程
- 分页加载:评论分页展示
- 用户管理:用户注册、登录、个人信息管理
- JWT 身份认证:安全的身份验证机制
- 用户主页:展示用户文章、关注/粉丝列表
- 三级权限:普通用户、管理员、超级管理员
- 关注系统:关注/取消关注其他用户
- 互相关注:双方关注后成为联系人
- 实时聊天:基于 WebSocket 的即时消息
- 支持私聊(互相关注用户无限制,非互相关注限2条未回复消息)
- 支持群聊(3人以上)
- 消息已读状态
- 未读消息提醒
- 创建群聊:从联系人中选择成员创建群聊(至少3人)
- 群管理:群主可转让群聊、设置管理员(最多3名)、邀请新成员
- 成员权限:普通成员无邀请权限
- 拉黑用户:阻止特定用户互动
- 双向限制:拉黑后双方无法查看对方内容、发送消息
- 适配桌面、平板、手机等各种设备屏幕
- 支持夜间模式,自动跟随系统主题
┌─────────────────────────────────────────────────────────────────┐
│ 客户端层(Frontend) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Vue 3 │ │ Vue Router │ │ Pinia │ │
│ │ 响应式框架 │ │ 路由管理 │ │ 状态管理 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Element Plus│ │ Axios │ │ Socket.io │ │
│ │ UI组件库 │ │ HTTP请求 │ │ 实时通信 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 服务端层(Backend) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Express │ │ Helmet │ │ CORS │ │
│ │ Web框架 │ │ 安全中间件 │ │ 跨域处理 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ JWT │ │ Multer │ │ Winston │ │
│ │ 身份认证 │ │ 文件上传 │ │ 日志系统 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 数据持久层(Database) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ MongoDB │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ User │ │ Article │ │ Comment │ │ Message │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
- 前后端分离:前端负责UI渲染和用户交互,后端提供纯API服务
- RESTful API:遵循REST架构风格,资源导向设计
- 无状态认证:使用JWT实现分布式友好认证机制
- 实时通信:WebSocket支持即时消息推送
- 安全优先:多层安全防护,包括Helmet、限流、XSS防护等
| 技术 | 版本 | 用途说明 |
|---|---|---|
| Vue 3 | 3.4.15 | 核心框架,采用Composition API |
| Vite | 5.0.11 | 构建工具,提供极速开发体验 |
| Vue Router | 4.2.5 | 单页面应用路由管理 |
| Pinia | 2.1.7 | 新一代状态管理库 |
| Element Plus | 2.5.1 | 企业级UI组件库 |
| Axios | 1.6.5 | HTTP请求库 |
| Socket.io-client | 4.8.3 | WebSocket客户端 |
| Marked | 11.1.1 | Markdown解析器 |
| Highlight.js | 11.9.0 | 代码高亮显示 |
| Day.js | 1.11.10 | 轻量级日期处理库 |
| DOMPurify | 3.0.8 | XSS防护库 |
| 技术 | 版本 | 用途说明 |
|---|---|---|
| Node.js | - | 运行时环境 |
| Express | 4.18.2 | Web应用框架 |
| MongoDB | - | NoSQL数据库 |
| Mongoose | 8.1.0 | MongoDB对象建模工具 |
| JWT | 9.0.2 | 身份认证令牌 |
| Bcryptjs | 2.4.3 | 密码加密库 |
| Socket.io | 4.8.3 | WebSocket服务端 |
| Multer | 1.4.5-lts.1 | 文件上传中间件 |
| Helmet | 7.1.0 | 安全HTTP头设置 |
| CORS | 2.8.5 | 跨域资源共享 |
| Compression | 1.7.4 | Gzip压缩中间件 |
| Express-rate-limit | 7.1.5 | API请求限流 |
| Winston | 3.11.0 | 日志管理库 |
- User:用户信息、关注关系、修改历史
- Article:文章内容、标签、点赞/收藏记录
- Comment:评论内容、回复关系
- Message:私信消息
- Conversation:会话记录、未读数
- Group:群聊信息、成员角色
- GroupMessage:群聊消息
- Follow:关注关系
- Blacklist:黑名单记录
- Notification:系统通知
- ActivityLog:活动日志
- Report:举报记录
- Node.js >= 16
- MongoDB >= 5.0
# 克隆项目
git clone <repository-url>
cd personal-blog
# 安装后端依赖
cd backend
npm install
# 安装前端依赖
cd ../frontend
npm install在 backend 目录下创建 .env 文件:
NODE_ENV=development
PORT=5000
MONGODB_URI=mongodb://localhost:27017/personal_blog
JWT_SECRET=your_secret_key_here
JWT_EXPIRE=7d
UPLOAD_PATH=./uploads
MAX_FILE_SIZE=5242880# 启动后端服务 (端口 5000)
cd backend
npm run dev
# 启动前端开发服务器 (端口 3000)
cd ../frontend
npm run dev访问 http://localhost:3000 查看应用
- 邮箱:admin@blog.com
- 密码:admin123
- 注意:首次登录后请立即修改密码
- 访问 http://localhost:3000/register 注册新账号
- 填写用户名(3-20个字符)、邮箱、密码
- 登录后可访问管理后台
- 首页:显示最新文章和热门标签
- 文章列表:支持按标签筛选、关键词搜索、分页浏览
- 文章详情:Markdown渲染、点赞、收藏、分享、评论
- 登录后可发表评论
- 评论按时间倒序排列
- 支持嵌套回复显示
登录后访问 http://localhost:3000/admin
创建文章:
- 点击"写文章"按钮
- 填写标题、分类、标签
- 使用Markdown格式编写内容
- 可上传图片(≤10MB)或视频(≤1GB)
- 可导入 .md/.markdown/.txt 文件
- 选择"存草稿"或"发布"
MD文件导入:
- 点击工具栏"导入"按钮
- 选择 .md、.markdown 或 .txt 文件
- 自动提取文件中的一级标题作为文章标题
- 如当前有内容会提示是否覆盖
文章状态:
- 草稿:仅作者可见,可继续编辑
- 待审核:等待管理员审核
- 已发布:对外可见
- 已归档:不再公开展示
- 修改用户名、简介、头像
- 修改密码(每周最多3次)
- 设置公开联系方式
| 方法 | 路径 | 描述 |
|---|---|---|
| POST | /api/auth/register | 用户注册 |
| POST | /api/auth/login | 用户登录 |
| GET | /api/auth/me | 获取当前用户信息 |
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /api/users/profile/:id | 获取用户资料 |
| PUT | /api/users/profile | 更新用户资料 |
| PUT | /api/users/password | 修改密码 |
| GET | /api/users/search | 搜索用户 |
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /api/articles | 获取文章列表 |
| GET | /api/articles/:id | 获取文章详情 |
| POST | /api/articles | 创建文章 |
| PUT | /api/articles/:id | 更新文章 |
| DELETE | /api/articles/:id | 删除文章 |
| POST | /api/articles/:id/like | 点赞文章 |
| POST | /api/articles/:id/favorite | 收藏文章 |
| 方法 | 路径 | 描述 |
|---|---|---|
| POST | /api/social/follow/:id | 关注用户 |
| DELETE | /api/social/follow/:id | 取消关注 |
| GET | /api/social/mutual-follows | 获取互相关注列表 |
| GET | /api/social/conversations | 获取会话列表 |
| GET | /api/social/messages/:userId | 获取消息记录 |
| POST | /api/social/messages/:userId | 发送消息 |
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /api/groups | 获取群聊列表 |
| POST | /api/groups | 创建群聊 |
| GET | /api/groups/:id | 获取群聊详情 |
| POST | /api/groups/:id/invite | 邀请成员 |
| POST | /api/groups/:id/admins | 设置管理员 |
| POST | /api/groups/:id/transfer | 转让群主 |
| 方法 | 路径 | 描述 |
|---|---|---|
| POST | /api/upload/image | 上传图片(≤10MB) |
| POST | /api/upload/video | 上传视频(≤1GB) |
const auth = async (req, res, next) => {
try {
const token = req.header('Authorization')?.replace('Bearer ', '');
if (!token) return res.status(401).json({ message: '未提供认证令牌' });
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const user = await User.findById(decoded.id);
if (!user || !user.isActive) {
return res.status(401).json({ message: '用户不存在或账户已被禁用' });
}
req.user = user;
next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(401).json({ message: '令牌已过期' });
}
res.status(500).json({ message: '服务器错误' });
}
};const initWebSocket = (httpServer) => {
io = new Server(httpServer, {
cors: { origin: '*', methods: ['GET', 'POST'] }
});
// JWT认证中间件
io.use(async (socket, next) => {
const token = socket.handshake.auth.token;
const decoded = jwt.verify(token, process.env.JWT_SECRET);
socket.userId = decoded.id;
next();
});
io.on('connection', (socket) => {
connectedUsers.set(socket.userId, socket.id);
socket.join(`user:${socket.userId}`);
});
};// 非互相关注用户最多发送2条未回复消息
if (!isMutualFollow) {
const unrepliedCount = await getUnrepliedMessageCount(senderId, receiverId);
if (unrepliedCount >= 2) {
socket.emit('message_error', {
message: '请静待对方回应',
code: 'WAIT_FOR_RESPONSE'
});
return;
}
}草稿(draft) → 待审核(pending) → 已发布(published)
↓
已拒绝(rejected) → 修改后重新提交
已发布(published) → 已归档(archived)
// 文章模型索引
articleSchema.index({ title: 'text', content: 'text' }); // 全文检索
articleSchema.index({ author: 1, createdAt: -1 }); // 作者文章列表
articleSchema.index({ status: 1, createdAt: -1 }); // 状态筛选
articleSchema.index({ tags: 1 }); // 标签查询// 全局限流:15分钟600次
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 600,
message: '请求过于频繁,请稍后再试'
});
// 社交API限流:1分钟120次
const socialLimiter = rateLimit({
windowMs: 60 * 1000,
max: 120
});- 路由懒加载:按需加载页面组件
- 图片懒加载:使用Intersection Observer API
- 代码分割:Vite自动代码分割
- Gzip压缩:服务端响应压缩
app.use(helmet()); // 安全HTTP头设置
app.use(compression()); // Gzip压缩
app.disable('x-powered-by'); // 禁用敏感头- 使用Bcrypt加密,12轮盐值
- 密码修改频率限制(每周最多3次)
- 用户名修改限制(每周最多2次)
- 邮箱/手机修改限制(每月最多1次)
// 前后端双重防护
import DOMPurify from 'dompurify';
const safeHtml = DOMPurify.sanitize(htmlContent);- 文件类型白名单验证
- 文件大小限制(图片10MB,视频1GB)
- 文件名随机化处理
personal-blog/
├── frontend/ # 前端项目 (Vue 3 + Vite)
│ ├── src/
│ │ ├── api/ # API 接口封装
│ │ ├── components/ # 公共组件
│ │ ├── composables/ # 组合式函数
│ │ ├── router/ # 路由配置
│ │ ├── services/ # 服务层 (WebSocket)
│ │ ├── stores/ # Pinia 状态管理
│ │ ├── utils/ # 工具函数
│ │ ├── views/ # 页面视图
│ │ │ ├── admin/ # 管理后台
│ │ │ └── ... # 前台页面
│ │ ├── App.vue
│ │ └── main.js
│ ├── package.json
│ └── vite.config.js
├── backend/ # 后端项目 (Express)
│ ├── middleware/ # 中间件 (认证、日志等)
│ ├── models/ # 数据模型
│ ├── routes/ # 路由定义
│ ├── scripts/ # 脚本工具
│ ├── utils/ # 工具函数
│ ├── uploads/ # 上传文件存储
│ ├── websocket.js # WebSocket 服务
│ ├── app.js # 应用入口
│ └── package.json
└── README.md
- 文章搜索优化(Elasticsearch全文搜索)
- 评论系统增强(楼中楼回复、评论点赞)
- 通知系统完善(站内通知、邮件通知)
- 云存储集成(阿里云OSS/腾讯云COS)
- 社交功能扩展(动态流、话题圈子)
- 数据分析面板
- 微服务架构改造
- 容器化部署(Docker + Kubernetes)
- 多端适配(小程序、移动App)
# 构建前端
cd frontend
npm run build
# 启动生产环境后端
cd ../backend
npm start- 设置环境变量
NODE_ENV=production - 配置 MongoDB 连接字符串
- 设置强密码的 JWT_SECRET
- 配置 Nginx 反向代理
A: 请检查邮箱地址、密码是否正确,网络连接是否正常
A: 请检查标题和内容是否已填写,网络连接是否正常
A: 请检查图片格式(jpg、png、gif、webp)和大小(≤10MB)
A: 请检查视频格式(mp4、webm、ogg、mov、avi、mkv)和大小(≤1GB)
MIT License
最后更新:2026-02-27