Markdown、D1、RSS 与站点地图:博客发布为什么要做四处一致性校验
Markdown、D1、RSS 与站点地图:博客发布为什么要做四处一致性校验
当博客同时使用仓库 Markdown、边缘数据库、RSS 和 sitemap 时,构建成功不代表文章真的上线。本文给出一套从内容源到生产回读的一致性发布方法。
一个现代博客可能同时有四个“文章存在”的判断来源:Git 仓库里的 Markdown、生产数据库中的文章记录、RSS feed,以及搜索引擎读取的 sitemap。
这四处只要有一处不同步,就会出现很迷惑的现象:代码已经提交,构建也成功,但文章页 404;首页能看到文章,RSS 却没有;浏览器能访问,搜索引擎却永远找不到。
四个表面分别负责什么
| 表面 | 主要职责 | 常见失败 |
|---|---|---|
| Markdown | 可审查的内容源与 Git 历史 | frontmatter 错误、slug 冲突 |
| D1 / SQLite | 生产运行时的数据查询 | migration 未打包或未执行 |
| RSS | 订阅器的新文章发现 | 缓存旧、过滤条件不同 |
| sitemap | 搜索引擎的页面发现 | 路径漏写、canonical 不一致 |
构建工具通常只保证代码能编译,不能保证这四个表面已经指向同一篇文章。
让 slug 成为稳定主键
文章标题可以调整,URL 最好保持稳定。可以用文件名生成 slug,并让 Markdown、数据库、RSS 和 sitemap 都引用同一个值:
content/posts/atomic-publishing.md
↓
slug = atomic-publishing
↓
/posts/atomic-publishing
数据库迁移使用 ON CONFLICT(slug) DO UPDATE,可以让重复部署变成幂等更新,而不是插入重复文章。
INSERT INTO posts (slug, title, content, date)
VALUES ('atomic-publishing', '原子发布', '...', '2026-08-24')
ON CONFLICT(slug) DO UPDATE SET
title = excluded.title,
content = excluded.content,
date = excluded.date,
updated_at = CURRENT_TIMESTAMP;
为什么迁移文件必须进入部署产物
本地仓库中存在 migration,不等于托管平台收到 migration。若打包过程只上传服务端 bundle 和静态资源,生产 Worker 能启动,但数据库里没有新文章。
因此产物检查至少要确认:
- 服务端入口存在;
- 托管元数据存在;
- 静态资源完整;
- 所有需要执行的 migration 位于平台约定目录;
.env、令牌和本地开发密钥没有被打包。
这一步检查的是“即将发布的包”,不能只检查源码目录。
构建成功不等于生产成功
一次可靠发布至少要经过三层证据:
1. 内容层
- Markdown frontmatter 可解析;
- slug、日期、标签和系列字段符合约定;
- migration 与 Markdown 正文一致;
- SQL 中的单引号等字符已正确转义。
2. 构建与数据层
- 生产构建成功;
- 本地空数据库能按顺序应用全部 migration;
- 重复应用时不会制造重复记录;
- 部署包包含数据库迁移且不含秘密文件。
3. 生产回读层
- 文章 URL 返回 HTTP 200;
- 页面包含本次文章的独特标题或 slug;
- 数据库健康接口返回已配置且可查询;
- RSS 返回 200 并包含新文章;
- sitemap 返回 200 并包含同一 URL。
只有部署任务显示绿色,而没有做生产回读,最多只能说明“平台接受了这次部署”。
不要只验证首页
首页往往有缓存、静态兜底或来自 Markdown 的列表,因此它显示新标题并不能证明文章详情已经进入数据库。
反过来,文章详情页能访问,也不能证明 RSS 与 sitemap 已更新。四个表面应该分别检查,而且要用文章的唯一 slug 做断言。
Article HTTP 200
RSS contains slug = true
Sitemap contains slug = true
Database configured = true
多篇文章如何批量发布
批量发布时可以为每篇文章生成独立、单调递增的 migration:
0013_article_a.sql
0014_article_b.sql
0015_article_c.sql
这样更容易审查、回滚和定位故障。最终回读时不要只抽查第一篇;数量不多时逐篇验证,数量较多时至少核对总数并对代表性文章做正文断言。
安全边界也属于发布质量
文章发布前要清理:
- 本机绝对路径和用户名;
.env、API Key、访问令牌和临时仓库凭据;- 未脱敏日志、Cookie、会话数据;
- 只在本地成立的内部地址;
- 不应该公开的第三方受保护文件内容。
Git 提交公开后很难真正抹掉历史,所以脱敏应该发生在提交之前,而不是部署之后。
结论
Markdown 是内容源,D1 是运行时记录,RSS 和 sitemap 是外部发现入口。真正的“文章已发布”意味着这四个表面在生产环境里指向同一份内容。
把检查写成固定流程后,博客发布就不再依赖“我打开首页好像看到了”,而是有一组可以重复执行、可以留证据、也能快速定位失败层级的验收标准。