:: 技术 0xBC // 技术分享

Typecho × Astro:把博客改成无头 CMS 架构的完整实践

F face 470 字 · 约 1 分钟 68 条评论 技术分享

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

#为什么要「无头」

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

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

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

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

#整体架构

text
┌─────────────┐    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
LCP 1.9s 0.4s
并发能力 受 PHP-FPM 限制 CDN 级别

#踩坑记录

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

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

本文链接:/post/typecho-astro-headless/ · 转载请注明出处 · 原文由 Typecho 驱动

//评论 68

  1. 访客甲

    访客甲 #4

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

    博主

    博主 #5

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

  2. 频率测试A

    频率测试A #6

    频率测试第一条 1791382170817

  3. 频率测试A

    频率测试A #7

    频率测试第一条 1791382312763

  4. 频率测试A

    频率测试A #8

    频率测试第一条 1791382410051

  5. 频率测试A

    频率测试A #9

    频率测试第一条 1791382422689

  6. 频率测试A

    频率测试A #10

    频率测试第一条 1791382435237

  7. 频率测试B

    频率测试B #11

    频率测试第二条(间隔<60s)

  8. 隔壁老王

    隔壁老王 #12

    已订阅 RSS,希望多更~

    半亩方塘

    半亩方塘 #14

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

  9. FastPHP

    FastPHP #13

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

  10. 半亩方塘

    半亩方塘 #15

    mark 一下,周末有空细读。

    沈青崖

    沈青崖 #16

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

    数字游民

    数字游民 #18

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

    FastPHP

    FastPHP #21

    楼上 +1,我也想知道。

    半亩方塘

    半亩方塘 #22

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

    猫爪敲键盘

    猫爪敲键盘 #33

    感谢解答,疑问解决了!

    猫爪敲键盘

    猫爪敲键盘 #45

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

    隔壁老王

    隔壁老王 #64

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

    隔壁老王

    隔壁老王 #24

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

    FastPHP

    FastPHP #17

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

    CC

    CC #19

    感谢解答,疑问解决了!

    CC

    CC #32

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

    夜航星

    夜航星 #20

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

    夜航星

    夜航星 #25

    感谢解答,疑问解决了!

    FastPHP

    FastPHP #30

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

    FastPHP

    FastPHP #58

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

$ 发表评论 visitor@typecho-astro-headless

// 相关阅读