起因
这次迁站一开始没打算动太多。我原本只是想把博客从 Hugo/Docsy 换到 Astro,顺便把页面样式和目录整理一下。
结果真开始动的时候才发现,站点和评论后台其实早就缠在一起了。站点这边有旧路由、样式入口和资源目录的问题,评论这边则是审核、通知和排查方式都太散。继续在旧结构上补补改改,后面只会越来越难看。
所以后来就不只是迁框架了,连评论后台也一起改了。现在回头看,真正花时间的是把那些以后还会反复碰到的地方一起改掉。
部署还是在 EdgeOne Pages;评论系统继续放在 Edge Functions + KV 上。
站点这边先说
迁到 Astro 以后,我先做的是把内容目录和路由收紧。
文章统一放到 src/content/posts/,前台路由也统一收进 /posts/*。旧地址没有直接丢掉,而是继续放在 public/_redirects 里做兼容,这样以前发出去的链接不会一下全断。
页面样式这次也一起拆了。主入口改到 src/styles/main.css,然后按用途分成 tokens.css、base.css、layout.css 和 components/*.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。
出问题时我一般先看哪里
这部分其实就是给自己留的值班笔记。以后再遇到类似问题,能少走一点回头路。
最常见的几个场景是:
-
评论提交返回
404 Comment path not allowed先看path有没有写成标准格式,再看allowed-paths里有没有这篇文章。如果是新文章,通常重新保存一次路径配置就能恢复。 -
管理后台返回
401 Unauthorized先确认ADMIN_PASSWORD配了没有,浏览器有没有带 Session Cookie,写操作有没有带X-CSRF-Token。如果开了 bearer fallback,再看Authorization头。 -
审核通过后前台还是看不到 先看评论是不是已经从 pending 挪到 approved,再看前台读取参数是不是打到了正确的 root。必要时可以临时开一次
COMMENT_APPROVED_INDEX_FALLBACK=1做排查。
如果真要回退,我自己的顺序通常是这样的:
- 先退配置:比如先把
REQUEST_LOG_ENABLED、SECURITY_ALERT_ENABLED、MAIL_ENABLED这些开关收回来。 - 再退发布版本:在 EdgeOne Pages 回到上一版,然后重新验证评论提交、审核和前台显示。
- 最后才碰数据:
kv-clear只在确认后执行,先 dry-run,再 execute。高风险操作之前先按 key 前缀导出一份备份。
最后
这次迁站最后留下来的,除了 Astro 这一套前台结构,更重要的是评论后台终于不再是一团临时拼出来的东西了。
以后再回来看这套站,页面怎么发、评论怎么审、日志在哪、KV 怎么查,基本都还找得到地方。这对我来说,比多加几个功能更重要。
Comments