在上篇文章《自研博客系统打造极致极简创作体验》中,我详细介绍了为什么选择自建博客系统以及整体的设计理念。经过一段时间的整理和优化,FlecBlog 终于开源出来了!这篇文章将作为技术特点的汇总,向大家展示这个项目的技术架构和核心实现。
FlecBlog 是一个完全自研的个人博客系统,由 Flec-Server(Go 后端)、Flec-Admin(Vue3 管理端)、Flec-Blog(Nuxt 博客端)三个子项目组成。项目从零开始独立开发,借鉴学习了大量开源系统后台,旨在打造一个真正符合个人习惯的一体化博客解决方案。

1 架构总览
| 层级 | 技术选型 | 版本 | 优势 |
|---|---|---|---|
| 后端 | Go | 1.25 | 性能优异、资源占用低、部署简单 |
| 管理端 | Vue | 3.5.29 | 生态熟悉、开发效率高、类型支持好 |
| 博客端 | Nuxt | 4.3.1 | SSR支持、SEO友好、Vue生态统一 |
| 数据库 | PostgreSQL | 14+ | 功能丰富、JSON支持好、无需额外缓存 |
整体架构采用前后端分离设计,后端提供 RESTful API,博客端和管理端通过 API 进行数据交互。数据库选型上坚持使用 PostgreSQL,利用其丰富的数据类型和 JSON 支持,可以避免引入额外的缓存和搜索组件。
2 后端
2.1 分层架构设计
后端采用了清晰的分层架构设计,严格遵循依赖注入原则:
api/ # 路由和中间件层
├── v1/ # API 处理器
├── middleware/ # 中间件
└── router/ # 路由注册
internal/ # 业务逻辑层
├── dto/ # 数据传输对象
├── model/ # 数据模型
├── repository/ # 数据访问层
└── service/ # 业务逻辑层
pkg/ # 公共包
├── ai/ # AI服务封装
├── auth/ # OAuth认证
├── email/ # 邮件服务
├── upload/ # 文件上传
└── notification/ # 通知服务这种分层设计使得代码结构清晰,职责明确。Repository 层负责数据库操作,Service 层处理业务逻辑,Controller 层处理 HTTP 请求,通过依赖注入模式实现层间解耦。
2.2 中间件体系
项目实现了一套完整的API安全防护体系:
- JWT 认证中间件:支持 Access Token(7天)和 Refresh Token(30天)双 Token 机制
- 可选认证中间件:适用于支持游客和登录用户共存的接口(如评论、文件上传)
- RBAC 权限控制:超级管理员、管理员、普通用户、游客四级权限体系
- 限流中间件:基于 IP、用户 ID 或全局的多种限流策略,返回标准限流响应头
- CORS 中间件:支持配置化白名单,允许携带凭据
2.3 统一存储抽象
项目实现了一套统一的文件存储抽象接口,支持多种存储方案:
type Storage interface {
Save(reader io.Reader, path string) error
Delete(path string) error
Exists(path string) bool
GetURL(path string, host string) string
}通过统一的配置,可以无缝切换以下存储后端:
- 本地存储
- AWS S3
- 腾讯云 COS
- 阿里云 OSS
- 七牛云 Kodo
- Cloudflare R2
- MinIO 自建
这种设计使得存储方案的选择完全配置化,无需修改代码。
2.4 OAuth 多元化登录
项目内置支持多种第三方登录方式:
- GitHub
- Microsoft
针对国内服务器部署场景,通过 Cloudflare Worker 代理解决服务端调用海外 OAuth API 的网络连通性问题:
// 将 OAuth API 请求转发到代理地址
prefixes := map[string]string{
"github.com": "/github",
"accounts.google.com": "/google",
}2.5 通知系统
通知系统实现了多渠道推送:
- 邮件通知:采用滑动时间窗口限流,每个邮箱每小时最多发送 5 封
- 飞书卡片消息:支持交互式卡片,当收到友链申请、新评论、RSS 订阅等事件时,飞书会推送带有操作按钮的卡片消息,管理员无需切换到博客后台,直接在卡片上点击即可完成审批、回复等操作,真正实现消息即操作台的移动端运维体验
2.6 微信公众号文章导出
这是一个非常实用的功能,可以将 Markdown 文章导出为微信公众号兼容格式:
- HTML 白名单标签过滤
- 内联样式转换(微信不支持外部 CSS)
- 代码块换行符转换
- 自定义块语法转换(提示框、折叠面板、标签页等)
3 管理端
3.1 双Token刷新机制
前端请求封装实现了完善的 Token 管理:
// 防止惊群效应的请求队列
let isRefreshing = false
let failedQueue: Array<{ resolve: Function; reject: Function }>[]
// 401时自动刷新,刷新期间将请求加入队列
const processQueue = (error: any = null) => {
failedQueue.forEach(promise => {
if (error) promise.reject(error)
else promise.resolve()
})
}这种设计确保了多个并发请求触发 401 时,只会有一个刷新 Token 的请求,避免了惊群效应。
3.2 CodeMirror 编辑器
这是管理端最核心的组件,实现了以下高级功能:
- 实时预览 :分屏模式下编辑区与预览区双向滚动同步,支持四种视图模式切换
- 图片处理 :粘贴图片自动上传、在线图片 URL 一键下载转存
- 扩展语法 :提示框、标签页、折叠面板、链接卡片、照片墙等自定义块
- 辅助功能 :字数统计、阅读时长估算、目录提取、表情选择器、全屏模式
3.3 数据可视化仪表板
基于 ECharts 构建的数据仪表板,提供全方位的运营数据展示:
- 访问趋势图 :支持日/月维度切换,展示浏览量与访客量双曲线
- 分类统计饼图 :文章分类分布可视化
- 标签云 :热门标签词云展示
- 文章贡献日历 :类似 GitHub 贡献图,直观展示写作频率
4 博客端
4.1 渲染与性能优化
博客端基于 Nuxt 4 构建,从渲染层到资源加载进行了全方位优化:
- SSR 服务端渲染,首屏 HTML 直出,配合 Critters 关键 CSS 内联减少渲染阻塞
- PWA 离线缓存,图片资源 CacheFirst 策略,缓存 30 天,每小时自动检查更新
- 图片懒加载,优先加载可视区域内容
代码分割采用细粒度策略,将第三方库按功能拆分:
manualChunks(id) {
if (id.includes('vue/')) return 'vue-core'
if (id.includes('markdown-it')) return 'markdown-renderer'
if (id.includes('highlight.js')) return 'highlight'
if (id.includes('remixicon')) return 'remixicon'
}首屏只加载核心代码,其他模块按需加载。
4.2 SEO 与开放生态
- 动态 Sitemap:构建时从 API 获取文章、分类、标签数据,自动生成站点地图
- 页面级 SEO:每篇文章配置 title、description、Open Graph、Twitter Card 标签
- 结构化数据:集成 Schema.org,提供文章发布时间、修改时间、封面图等信息
- RSS 订阅:提供 Atom Feed,支持 RSS 阅读器订阅
- 多渠道订阅:公众号、邮件、RSS 三种方式,邮件订阅支持一键退订
4.3 交互功能集成
- 评论系统:支持游客评论和登录评论,多级回复、引用回复、表情选择器
- 全局搜索:500ms 防抖,关键词高亮,分页展示
- 图片预览:集成 medium-zoom,点击全屏预览,支持缩放拖拽
- 平滑滚动:集成 Lenis,自定义缓动函数,滚动更流畅
- 反馈系统:用户反馈投诉入口,收集意见持续改进
- 文章阅读:封面模糊化处理,元数据完善,AI 摘要速读,沉浸阅读模式
4.4 特色页面展示
- 关于页面:个人介绍、性格测试、座右铭、联系方式、站点统计、访问统计
- 友链页面:卡片式布局,分组管理,失效友链标记,在线申请入口
- 动态页面:瀑布流布局,支持图片/视频/音乐/链接分享,图片缩放预览
- 协议页面:隐私政策、Cookie 政策、版权协议
5 快速部署
强烈推荐使用 Docker Compose 一键部署,通过简单的配置文件,统一管理和启动三端服务,极大简化了部署流程。
- 创建 .env 文件:
# Database Configuration
DB_PASSWORD=your_database_password
# JWT Configuration
JWT_SECRET=your_jwt_secret_key
# Site Configuration
API_URL=https://api.yourdomain.com/api/v1- 创建 docker-compose.yml 文件,使用外部 PostgreSQL 数据库:
services:
server:
image: talen8/flec-server:latest
container_name: flec_server
restart: unless-stopped
environment:
DB_HOST: localhost
DB_PORT: 5432
DB_NAME: postgres
DB_USER: postgres
DB_PASSWORD: ${DB_PASSWORD}
JWT_SECRET: ${JWT_SECRET}
ports:
- "8080:8080"
volumes:
- /srv/docker/flec_server:/app/data
networks:
- flec-network
blog:
image: talen8/flec-blog:latest
container_name: flec_blog
restart: unless-stopped
environment:
NUXT_PUBLIC_API_URL: ${API_URL}
ports:
- "3000:3000"
networks:
- flec-network
depends_on:
- server
admin:
image: talen8/flec-admin:latest
container_name: flec_admin
restart: unless-stopped
environment:
API_URL: ${API_URL}
ports:
- "4000:4000"
networks:
- flec-network
depends_on:
- server
networks:
flec-network:
driver: bridgeservices:
postgres:
image: postgres:15-alpine
container_name: flec_postgres
restart: unless-stopped
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- flec-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
server:
image: talen8/flec-server:latest
container_name: flec_server
restart: unless-stopped
environment:
DB_HOST: postgres
DB_PORT: 5432
DB_NAME: postgres
DB_USER: postgres
DB_PASSWORD: ${DB_PASSWORD}
JWT_SECRET: ${JWT_SECRET}
ports:
- "8080:8080"
volumes:
- /srv/docker/flec_server:/app/data
networks:
- flec-network
depends_on:
postgres:
condition: service_healthy
blog:
image: talen8/flec-blog:latest
container_name: flec_blog
restart: unless-stopped
environment:
NUXT_PUBLIC_API_URL: ${API_URL}
ports:
- "3000:3000"
networks:
- flec-network
depends_on:
- server
admin:
image: talen8/flec-admin:latest
container_name: flec_admin
restart: unless-stopped
environment:
API_URL: ${API_URL}
ports:
- "4000:4000"
networks:
- flec-network
depends_on:
- server
networks:
flec-network:
driver: bridge
volumes:
postgres_data:- 启动服务:
docker-compose up -d-
访问地址:
6 写在最后
FlecBlog 作为一个完全自研的个人博客系统,从技术选型到功能实现,尽力坚持着轻的原则。极简的视觉设计、一体化的功能体验、完全个人化的操作习惯,这些都是我在两年多博客搭建过程中不断打磨的成果。
项目已正式开源,如果你:
- 想搭建一个完全自主的博客系统
- 对技术实现感兴趣,想学习 Go+Vue 技术栈
- 正在寻找一个可深度定制的博客方案
欢迎访问 GitHub 仓库,了解更多细节。
如果这个项目对你有帮助,欢迎 star 支持一下!有任何问题也欢迎在评论区提出。
评论