G
GoldenHovers
技术 •

从 Notion 崩溃到 Astro+CF 纯静态秒开:个人博客内核重构与踩坑全纪实

记录一次将挂掉的 Notion 动态博客重构为 Astro SSG + Keystatic + Cloudflare Pages 的完整实战。包含为什么不用 GitHub 存音频的架构推演,以及 3 个实打实的部署避坑细节。

从 Notion 崩溃到 Astro+CF 纯静态秒开:个人博客内核重构与踩坑全纪实

1. 背景与痛点:为什么旧博客会暴毙?

之前的个人博客(挂载在二级域名 blog.goldenhoversnet.dpdns.org 上)突然无法访问。排查下来,根因是原方案严重依赖外部动态拉取与第三方中转(如 Notion API / 动态渲染脚本)。

这类基于外部 SaaS 数据库的轻量博客方案虽然刚开始建站省事,但存在几个致命的架构脆弱点:

  1. API 鉴权与 Schema 极脆弱:第三方平台接口稍有变动、Token 过期或匿名请求频率超标(Rate Limit),前台立刻暴毙白屏;
  2. 多层网络链路衰减:访客 ➔ CDN ➔ 中转 Worker ➔ Notion 数据库,首屏加载存在明显的冷启动和网络等待;
  3. 数据主权不在手:一旦接口失效,连排版带文章直接失联。

因此,今天决定彻底换掉博客内核:重构为现代纯静态生成(SSG)体系,结合可视化本地写作后台,并托管于 Cloudflare Pages 全球 CDN。


2. 架构推演与技术选型

2.1 为什么是 Astro + Keystatic?

重构的目标很明确:前台必须快、架构必须抗造、零数据库维护成本、随时想写就写。

备选方案优点缺点结论
WordPress / Ghost功能大而全,后台成熟必须常驻一台 VPS 服务器和 MySQL,维护繁琐且消耗机器资源❌ 过于笨重
纯静态 Hexo / Hugo编译快、纯静态极速缺少可视化后台,必须在代码编辑器里写,排版不够直观⚠️ 写作体验不够丝滑
Astro + Keystatic (最终选型)前台纯静态零 JS 负担,自带类 Notion 的富文本/Markdown 编辑后台本地需 Node 环境支撑开发后台✅ 最佳平衡:前台极速 + 本地可视化写作

2.2 延伸推演:为什么音频资源不能学大肥鱼存 GitHub?

在讨论架构时,我们还研判了另一个开源站点「蓝色大肥鱼(bluedafeiyu)」,探讨是否能将游戏 Mod(《杀戮尖塔 2》联机音乐 DJ)的几百兆音频顺便从 Cloudflare 迁到 GitHub 仓库?

实测推演结论:绝对不行!

  1. 单体体积与 Git 膨胀:
    • 大肥鱼存的是表情包图片(单张 100~300KB),Git 处理增量极轻;
    • 音乐文件动辄 330MB,Git 追踪大体积二进制文件会导致仓库瞬间膨胀数个 GB,极易触发 GitHub 12GB 限制警告甚至封号。
  2. 国内网络连通性是致命伤:
    • raw.githubusercontent.com 在国内被严重的 DNS 污染与防火墙阻断。实测直接拉取全部超时;若换到 GitHub,国内 Mod 玩家进游戏将 100% 下载失败;
    • 相反,Cloudflare Pages 原生支持音频 HTTP Range Requests(分片串流),全国节点分发速度与稳定性远超 GitHub。

3. 核心实现架构

flowchart LR
    subgraph 本地写作端
        A[双击 start.bat] --> B[Astro Local Dev: 4321]
        B --> C[Keystatic 可视化后台 /keystatic]
        C -->|拖拽传图/排版保存| D[本地 src/content/posts/*.md]
    end

    subgraph 编译与云端交付
        D --> E[双击 deploy.bat]
        E --> F[Astro SSG 纯静态构建 dist/]
        F --> G[Wrangler 增量推送]
        G --> H[Cloudflare Pages: goldenhovers-blog]
        H --> I[https://goldenhovers-blog.pages.dev]
    end

    I -.->|双向互通| J[🎮 贪吃蛇小游戏主站]

为了让平时写作和部署彻底摆脱繁杂命令,我们封装了双击即用的环境:

  • start.bat:一键拉起本地开发服务,自动打开前台与 Keystatic 后台;
  • deploy.bat:一键调用 npm run build 预编译 9 个静态页面,并使用 Wrangler 增量推送到 Cloudflare 边缘节点。

4. 真实排错实录(血泪避坑三则)

在初次执行 deploy.bat 上线时,我们遇到了 3 个非常典型但极具隐蔽性的问题:

4.1 坑点一:Wrangler 探测 Cloudflare 账号超时

  • 现象:
    X [ERROR] Failed to automatically retrieve account IDs for the logged in user.
  • 根因分析: 在配置了系统代理的机器上,Wrangler 尝试自动调用 Cloudflare API 检索绑定的多账号列表时触发了鉴权超时。
  • 解决方案: 无需每次网络探测,直接在 deploy.bat 中注入固定的环境变量:
    set "CLOUDFLARE_ACCOUNT_ID=b441e937fb951e1493b55adb3d4ecb3a"

4.2 坑点二:云端 Pages 专属项目未初始化 (Code: 8000007)

  • 现象:
    X [ERROR] A request to the Cloudflare API failed: Project not found [code: 8000007]
  • 根因分析: 账户此前只有用于主站的 my-first-site 项目,全新的 goldenhovers-blog 在云端不存在,直接 pages deploy 会被拒绝。
  • 解决方案: 先执行一次项目初始化指令:
    wrangler pages project create goldenhovers-blog --production-branch=master
    随后即可无缝增量部署。

4.3 坑点三:Keystatic 默认生成 .mdoc 导致 Astro 路由丢失

  • 现象: 在后台新建文章并保存后,运行编译只输出了原有页面,新文章完全没有生成对应 HTML。
  • 根因分析: Keystatic 默认的 fields.document 生成的是 Markdoc 格式(.mdoc),而 Astro 默认只为 .md 和 .mdx 生成静态集合路由。
  • 解决方案: 修改 keystatic.config.mjs,显式指定编辑器输出格式为标准 .md:
    content: fields.markdoc({
      label: '正文内容',
      extension: 'md',
      options: { /* 图片目录与常用排版配置 */ }
    })
    修改后,文章完美被识别,秒级渲染出静态详情页。

5. 验收成果与后续规划

  1. 秒开与零成本:构建耗时仅 2.76 秒,生成 9 个纯静态页面并秒级推送至全球 CDN,访问延迟从数百毫秒压缩到数十毫秒;
  2. 主站无缝互联:贪吃蛇小游戏主页(goldenhoversnet.dpdns.org)右上角直达新博客,博客顶部一键回切小游戏;
  3. 数据百分之百属于自己:全站所有博文均以标准 Markdown 存储在本地 Git 仓库,彻底告别外部 API 崩溃的恐慌。

后续演进建议: 后续若有在手机端随手发文的高频需求,可将本地仓库推送至 GitHub,打通基于 GitHub 授权的无服务器移动端发文链路。目前基于本地 start.bat + deploy.bat 的离线安全流已完全满足日常深度创作需求!