把用了多年的 Typecho 保留为后台内容管理,前端换成 Astro 静态渲染——这就是本站现在的架构。这篇文章记录完整的改造思路与踩坑。

为什么要「无头」

传统的 Typecho 主题由 PHP 直接渲染,存在几个痛点:

  1. 页面性能受制于服务器与 PHP 执行速度
  2. 前端工程化(组件化、按需构建、Tree Shaking)无从谈起
  3. 难以复用同一份内容做小程序、App 等多端输出

无头(Headless)方案把内容与展示彻底分离:

Typecho 负责内容存储与管理后台,Astro 负责高性能展示层,两者通过 API 通信。

整体架构

┌─────────────┐    RESTful API    ┌──────────────┐
│   Typecho   │ ───────────────▶  │     Astro    │
│  (内容管理)  │   getarticle …   │  (静态构建)   │
└─────────────┘                   └──────────────┘
       ▲                                  │
       │   评论提交(令牌代理)              │
       └──────────────────────────────────┘

构建期,Astro 通过分页接口拉取全部文章并预渲染为静态页面;运行期,评论列表与搜索通过轻量 API 路由实时转发,保证「新内容即时可见」。

关键实现

评论的令牌代理

Typecho 从 1.2 起给评论表单加了反垃圾令牌:_ = md5(secret + '&' + 页面URL)。无头站点的服务端代理按下面三步处理:

  1. 抓取文章页 HTML,还原内嵌令牌
  2. 以该页面 URL 作为 Referer
  3. 转发评论字段到原生 /comment 端点

性能对比

同一篇文章在两种架构下的表现(实测本站):

指标PHP 直渲染Astro 静态
首屏 TTFB~180ms~12ms
LCP1.9s0.4s
并发能力受 PHP-FPM 限制CDN 级别

踩坑记录

  • 插件返回的 text 是 原始 Markdown,带 <!--markdown--> 前缀,需要前端自行渲染
  • 评论令牌绑定的是「抓取时的 URL」,Referer 必须与之一致
  • 中文分类会自动生成中文 slug,URL 里记得做 encodeURIComponent
# 检查 API 是否正常
curl -s "https://example.com/index.php/api?token=***&method=getbloginfo" | jq

总结:无头改造后,写作流程没有变化,但前端获得了现代工程化的一切。值得折腾。

标签: Typecho, Astro, 无头CMS, 架构

已有 68 条评论

  1. 访客甲 访客甲

    架构思路很清晰,正好在考虑把老博客做无头改造,收藏了!

    1. 博主 博主

      欢迎交流,评论区就是用文中提到的令牌代理方案实现的。

  2. 频率测试A 频率测试A

    频率测试第一条 1791382170817

  3. 频率测试A 频率测试A

    频率测试第一条 1791382312763

  4. 频率测试A 频率测试A

    频率测试第一条 1791382410051

  5. 频率测试A 频率测试A

    频率测试第一条 1791382422689

  6. 频率测试A 频率测试A

    频率测试第一条 1791382435237

  7. 频率测试B 频率测试B

    频率测试第二条(间隔

  8. 隔壁老王 隔壁老王

    已订阅 RSS,希望多更~

    1. 半亩方塘 半亩方塘

      哈哈,跟我理解的一样,放心用了。

  9. FastPHP FastPHP

    写得很清楚,收藏了,回头照着实践一遍。

  10. 半亩方塘 半亩方塘

    mark 一下,周末有空细读。

    1. 沈青崖 沈青崖

      插个楼:实测下来数据量大了之后要注意缓存。

      1. 数字游民 数字游民

        哈哈,跟我理解的一样,放心用了。

      2. FastPHP FastPHP

        楼上 +1,我也想知道。

        1. 半亩方塘 半亩方塘

          插个楼:实测下来数据量大了之后要注意缓存。

          1. 猫爪敲键盘 猫爪敲键盘

            感谢解答,疑问解决了!

        2. 猫爪敲键盘 猫爪敲键盘

          作者回复得真快,体验好评。

        3. 隔壁老王 隔壁老王

          这个问题我踩过,翻我博客有篇笔记专门讲这个。

      3. 隔壁老王 隔壁老王

        这么一看确实是版本差异导致的,结案。

    2. FastPHP FastPHP

      这个问题我踩过,翻我博客有篇笔记专门讲这个。

    3. CC CC

      感谢解答,疑问解决了!

      1. CC CC

        补充一点:官方文档里其实有提到这个边界情况。

    4. 夜航星 夜航星

      插个楼:实测下来数据量大了之后要注意缓存。

    5. 夜航星 夜航星

      感谢解答,疑问解决了!

      1. FastPHP FastPHP

        插个楼:实测下来数据量大了之后要注意缓存。

        1. FastPHP FastPHP

          作者回复得真快,体验好评。

  11. 半亩方塘 半亩方塘

    有几个细节想深入聊聊,已发邮件到你邮箱。

  12. 夜航星 夜航星

    第一次见把 Typecho 玩成无头 CMS 的,涨知识了。

    1. 夜航星 夜航星

      楼上 +1,我也想知道。

    2. 夜航星 夜航星

      楼上 +1,我也想知道。

  13. FastPHP FastPHP

    mark 一下,周末有空细读。

    1. 沈青崖 沈青崖

      学到了,回頭我也整理一篇。

  14. 沈青崖 沈青崖

    写得很清楚,收藏了,回头照着实践一遍。

    1. 沈青崖 沈青崖

      作者回复得真快,体验好评。

  15. FastPHP FastPHP

    请问评论这套代理方案的性能如何?延迟大不大?

    1. FastPHP FastPHP

      同问,蹲一个回复。

  16. 猫爪敲键盘 猫爪敲键盘

    正文里的对比表格很直观,数据是实测的吗?

  17. 猫爪敲键盘 猫爪敲键盘

    踩过同样的坑,评论区补充一下:中文 slug 记得做 encode。

  18. CC CC

    有几个细节想深入聊聊,已发邮件到你邮箱。

  19. CC CC

    请问博主,这套方案在多实例部署下要注意什么?

  20. 半亩方塘 半亩方塘

    写得很清楚,收藏了,回头照着实践一遍。

  21. 夜航星 夜航星

    静默读了三遍,第三遍才注意到文末的彩蛋。

  22. CC CC

    卧槽,这个令牌代理的思路太秀了。

    1. CC CC

      这个问题我踩过,翻我博客有篇笔记专门讲这个。

  23. CC CC

    参考你这篇把备案和 CDN 也配置好了,感谢!

  24. 夜航星 夜航星

    正文里的对比表格很直观,数据是实测的吗?

  25. 隔壁老王 隔壁老王

    参考你这篇把备案和 CDN 也配置好了,感谢!

  26. 半亩方塘 半亩方塘

    转发到群里了,同事们都说有用。

  27. CC CC

    踩过同样的坑,评论区补充一下:中文 slug 记得做 encode。

  28. 沈青崖 沈青崖

    踩过同样的坑,评论区补充一下:中文 slug 记得做 encode。

  29. 数字游民 数字游民

    转发到群里了,同事们都说有用。

  30. FastPHP FastPHP

    第一次见把 Typecho 玩成无头 CMS 的,涨知识了。

  31. 隔壁老王 隔壁老王

    踩过同样的坑,评论区补充一下:中文 slug 记得做 encode。

  32. 沈青崖 沈青崖

    正文里的对比表格很直观,数据是实测的吗?

  33. 数字游民 数字游民

    来了来了,坐等更新系列下一篇。

  34. CC CC

    第一次见把 Typecho 玩成无头 CMS 的,涨知识了。

  35. 隔壁老王 隔壁老王

    配图和排版都很舒服,阅读体验极佳。

  36. CC CC

    配图和排版都很舒服,阅读体验极佳。

  37. 沈青崖 沈青崖

    技术选型的部分写得挺中肯,不是无脑吹。

  38. CC CC

    看完直接把我的旧博客迁移计划提上日程了。

  39. 沈青崖 沈青崖

    配图和排版都很舒服,阅读体验极佳。

  40. 频率测试A 频率测试A

    频率测试第一条 1791382955199

  41. 频率测试B 频率测试B

    频率测试第二条(间隔

  42. 频率测试A 频率测试A

    频率测试第一条 1791382974163

  43. 频率测试A 频率测试A

    频率测试第一条 1791383018046

  44. 频率测试B 频率测试B

    频率测试第二条(间隔

  45. 频率测试A 频率测试A

    频率测试第一条 1791383189226

添加新评论