AI 摘要
AI
正在生成摘要...

在上篇文章《自研博客系统打造极致极简创作体验》中,我详细介绍了为什么选择自建博客系统以及整体的设计理念。经过一段时间的整理和优化,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 分层架构设计

后端采用了清晰的分层架构设计,严格遵循依赖注入原则:

TEXT
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 统一存储抽象

项目实现了一套统一的文件存储抽象接口,支持多种存储方案:

GO
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
  • Google
  • QQ
  • Microsoft

针对国内服务器部署场景,通过 Cloudflare Worker 代理解决服务端调用海外 OAuth API 的网络连通性问题:

GO
// 将 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 管理:

TYPESCRIPT
// 防止惊群效应的请求队列
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 天,每小时自动检查更新
  • 图片懒加载,优先加载可视区域内容

代码分割采用细粒度策略,将第三方库按功能拆分:

JAVASCRIPT
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 一键部署,通过简单的配置文件,统一管理和启动三端服务,极大简化了部署流程。

  1. 创建 .env 文件:
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
  1. 创建 docker-compose.yml 文件,使用外部 PostgreSQL 数据库:
使用外部PostgreSQL的简化配置(点击展开)
YAML
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: bridge
包含PostgreSQL的完整配置(点击展开)
YAML
services:
  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:
  1. 启动服务:
BASH
docker-compose up -d
  1. 访问地址:

6 写在最后

FlecBlog 作为一个完全自研的个人博客系统,从技术选型到功能实现,尽力坚持着的原则。极简的视觉设计、一体化的功能体验、完全个人化的操作习惯,这些都是我在两年多博客搭建过程中不断打磨的成果。

项目已正式开源,如果你:

  • 想搭建一个完全自主的博客系统
  • 对技术实现感兴趣,想学习 Go+Vue 技术栈
  • 正在寻找一个可深度定制的博客方案

欢迎访问 GitHub 仓库,了解更多细节。

如果这个项目对你有帮助,欢迎 star 支持一下!有任何问题也欢迎在评论区提出。

评论