博客迁到 Astro ,kv实现评论系统

Feb 13, 2026 | 8 min

起因

这次迁站一开始没打算动太多。我原本只是想把博客从 Hugo/Docsy 换到 Astro,顺便把页面样式和目录整理一下。

结果真开始动的时候才发现,站点和评论后台其实早就缠在一起了。站点这边有旧路由、样式入口和资源目录的问题,评论这边则是审核、通知和排查方式都太散。继续在旧结构上补补改改,后面只会越来越难看。

所以后来就不只是迁框架了,连评论后台也一起改了。现在回头看,真正花时间的是把那些以后还会反复碰到的地方一起改掉。

部署还是在 EdgeOne Pages;评论系统继续放在 Edge Functions + KV 上。

站点这边先说

迁到 Astro 以后,我先做的是把内容目录和路由收紧。

文章统一放到 src/content/posts/,前台路由也统一收进 /posts/*。旧地址没有直接丢掉,而是继续放在 public/_redirects 里做兼容,这样以前发出去的链接不会一下全断。

页面样式这次也一起拆了。主入口改到 src/styles/main.css,然后按用途分成 tokens.cssbase.csslayout.csscomponents/*.css 这些文件。文章详情页另放到 public/styles/post-detail.css,避免所有东西都继续往一份全局样式里堆。

封面资源和随机逻辑也重新摆了一下:图片在 public/covers/*,随机取图逻辑在 src/lib/covers.ts。这一点不复杂,但改完以后目录清楚很多,回头找资源时不会到处翻。

另外我把节庆那一层也保留了下来。ThemeLayout.astro 负责装主题壳和运行时变量,节庆模板在 src/festival/templates.ts,配置在 src/site.config.ts。这部分不是迁站的重点,但既然动了主布局,索性一起清掉。

评论系统这次一起重写

真正耗时间的是评论后台。以前那套不是不能用,只是审核、通知和排障都太散,隔一阵子再回来就得重新找。

这次改完以后,公开接口和管理接口大致是下面这些:

方法路径用途权限
POST/api/comments提交评论,先进入 pending公开
GET/api/comments读取已审核评论公开
GET/api/admin/comments/paths查看哪些文章还有待审核评论管理
GET/api/admin/comments/pending拉取待审核评论队列管理
POST/api/admin/comments/approve通过评论管理
POST/api/admin/comments/reject拒绝评论管理
GET/POST/api/admin/comments/allowed-paths读取或更新评论路径白名单管理
POST/api/admin/comments/author-token签发作者 token管理
POST/api/admin/comments/kv-clear做 KV 清理,支持 dry-run/execute管理

后端结构我没有再追求花哨,基本还是老老实实分了几层:

  • 路由层接请求,做基本校验。
  • 鉴权、来源校验、作者 token 这类逻辑放在 _lib 里。
  • pending 和 approved 各自有存储层,负责分页索引和线程读取。
  • path 归一化和 KV key 规则单独放在 kv-keys.js
  • 日志、告警和邮件通知放在运行层。

KV 里也重新分了前缀。pending、approved、thread、roots、rate-limit、duplicate-window 这些各走各的,不再混在一起。以后查数据、删数据、看索引时,会比原来直接得多。

还有一件事这次也一起补了:评论对象不再一份数据到处传。前台、后台和日志现在是三种视图。前台只拿展示字段,后台拿审核需要的字段,日志只保留足够排查的快照,不把正文和原始 IP 全塞进去。

这次一起补上的安全项

迁站的时候把安全项一起补完,反而比较省心,因为不用等上线以后再一条条补洞。

现在管理后台走的是 ADMIN_PASSWORD + Session Cookie + CSRF,旧的 bearer 兼容只在 ADMIN_BEARER_FALLBACK=1 时短期开启。公开评论提交这边加了同源校验,请求来源不对就直接拒绝;另外还补了请求体大小限制、UTF-8 字节校验、honeypot、关键词和 URL 主机检查、频率限制,以及重复提交检测。

kv-clear 也不再是一个危险按钮点下去就算完。现在必须先 dry-run,再 execute,还要带确认词和理由,至少不会在脑子不清楚的时候一把把数据删掉。

日志和环境变量

日志这块我这次没做复杂。原因也很现实:EdgeOne 对 Edge Functions 的日志展示还不算特别好用,所以 REQUEST_LOG_ENABLED 我默认还是关着,等平台侧再完整一点再说。

现在我本地一直用的是这组基线:

ADMIN_PASSWORD=REPLACE_WITH_DEV_ADMIN_PASSWORD
ADMIN_SESSION_COOKIE_NAME=eo_admin_sid
ADMIN_SESSION_IDLE_TTL_SECONDS=28800
ADMIN_SESSION_ABSOLUTE_TTL_SECONDS=604800
ADMIN_BEARER_FALLBACK=0
ADMIN_ALLOWED_ORIGINS=http://localhost:4321,http://127.0.0.1:4321
ADMIN_ALLOW_MISSING_ORIGIN=0
AUTHOR_TOKEN_SECRET=REPLACE_WITH_DEV_AUTHOR_SECRET
REQUEST_LOG_ENABLED=0
SECURITY_ALERT_ENABLED=0

真正上线以后,再按需要把 SECURITY_ALERT_ENABLED=1、告警 webhook 和邮件相关变量补上。

这里最容易忘的几个变量是:

  • ADMIN_PASSWORD:后台登录口令。
  • ADMIN_ALLOWED_ORIGINS:后台接口来源白名单。
  • AUTHOR_TOKEN_SECRET:作者 token 的签发密钥,别和 admin token 混用。
  • REQUEST_LOG_ENABLED:控制请求日志输出,默认关着。
  • SECURITY_ALERT_ENABLED:控制安全告警 webhook。

出问题时我一般先看哪里

这部分其实就是给自己留的值班笔记。以后再遇到类似问题,能少走一点回头路。

最常见的几个场景是:

  1. 评论提交返回 404 Comment path not allowed 先看 path 有没有写成标准格式,再看 allowed-paths 里有没有这篇文章。如果是新文章,通常重新保存一次路径配置就能恢复。

  2. 管理后台返回 401 Unauthorized 先确认 ADMIN_PASSWORD 配了没有,浏览器有没有带 Session Cookie,写操作有没有带 X-CSRF-Token。如果开了 bearer fallback,再看 Authorization 头。

  3. 审核通过后前台还是看不到 先看评论是不是已经从 pending 挪到 approved,再看前台读取参数是不是打到了正确的 root。必要时可以临时开一次 COMMENT_APPROVED_INDEX_FALLBACK=1 做排查。

如果真要回退,我自己的顺序通常是这样的:

  • 先退配置:比如先把 REQUEST_LOG_ENABLEDSECURITY_ALERT_ENABLEDMAIL_ENABLED 这些开关收回来。
  • 再退发布版本:在 EdgeOne Pages 回到上一版,然后重新验证评论提交、审核和前台显示。
  • 最后才碰数据:kv-clear 只在确认后执行,先 dry-run,再 execute。高风险操作之前先按 key 前缀导出一份备份。

最后

这次迁站最后留下来的,除了 Astro 这一套前台结构,更重要的是评论后台终于不再是一团临时拼出来的东西了。

以后再回来看这套站,页面怎么发、评论怎么审、日志在哪、KV 怎么查,基本都还找得到地方。这对我来说,比多加几个功能更重要。

Comments

Email is only used for reply notifications and is never shown publicly.