ORTHANT 技术架构
ORTHANT 的技术选型和运行方式。
ORTHANT 用 Hugo 生成网页,部署在 Cloudflare Pages,Markdown 原稿保存在 GitHub。
博客由我个人维护,选 Cloudflare Pages 是为了省去服务器运维。
读者打开页面要快,评论和统计出问题也不该耽误阅读。所以正文在发布时就生成好,评论、计数这些功能单独加载。
1. 整体结构

| 部分 | 工具 | 用途 |
|---|---|---|
| 内容 | Markdown + Git,托管在 GitHub 私有仓库 | 文章、图片、网站模板,以及它们的全部修改历史 |
| 生成 | Hugo 和 Hextra 主题 | 生成网页、导航和搜索索引 |
| 托管 | Cloudflare Pages | 把生成好的网页发给读者 |
| 服务端 | Pages Functions | 站长登录、在线保存、阅读授权、评论管理、浏览计数 |
| 数据库 | Cloudflare D1 | 浏览次数,以及授权码的尝试记录 |
| 评论 | giscus + GitHub Discussions | 评论的显示和存储 |
网站收到的请求都会经过 Functions 的路径检查。公开页面交给静态服务返回,项目案例和附件还要检查阅读权限。登录、保存、评论管理和计数也由 Functions 处理。
Git 里保存的是 Markdown 原稿,Cloudflare 托管的是生成后的网页。D1 和讨论区不存文章正文。
2. 写作与发布
本地编辑器、GitHub 网页、博客里的在线编辑,都能用来改文章。在线编辑用过 Pages CMS,后来换成自己部署的 Decap CMS。
现在直接在文章页编辑:登录后点「编辑本文」,改完点「保存并发布」。保存流程如下:
- 服务端核对站长账号和仓库写权限。
- 检查文章版本。如果文章在编辑期间被别处修改,本次保存会停止,并提示重新打开对比。
- 正文和本次新插入的图片放进同一次 Git 提交。
- Cloudflare 收到主分支的新提交,用 Hugo 重新生成整站并部署。
- 浏览器对照线上构建清单,确认本次文章版本已部署,显示「文章已上线」。
提交成功和文章上线是两回事: GitHub 收到提交时,内容已经进仓库,离开编辑页不会中断部署,站内其他页面会继续显示状态。构建排队或失败时,新版本还没有上线。
3. 读者打开页面时
读者打开文章,Cloudflare 返回已经生成好的网页,访问时不用去 GitHub 读取正文或临时拼页面。
普通文章直接返回正文。项目案例需要阅读权限:没有权限时显示授权码页面,检查出错时显示暂时不可用,这两种情况都不返回案例正文。
附加功能按需加载:
- 浏览次数单独发请求获取。
- 页面快滚动到评论区时,才加载评论。
- 第一次打开搜索时,下载搜索索引。
- 文章页确认站长登录后显示编辑入口,进入编辑模式时加载编辑器。
这些功能出问题,已经显示的正文照样能读。
4. 站长、读者与评论者
| 身份 | 登录或授权方式 | 权限 |
|---|---|---|
| 站长 | 用 GitHub 账号登录 | 写文章、看项目案例、管理评论 |
| 授权读者 | 输入阅读授权码 | 看项目案例和附件 |
| 评论者 | 在评论区用 GitHub 授权 | 在公开文章下评论 |
站长通过只授权给博客仓库的 GitHub App 登录。登录状态加密后保存在浏览器里,最长 8 小时,服务端不单独保存会话。每次保存文章,服务端都会向 GitHub 重新核对权限,编辑按钮是否显示不决定能否写入。
阅读授权码是共享密码,验证通过后 8 小时内不用再输。拿到授权码的人能看全部案例,也能复制内容,所以写案例时仍要去掉不打算分享的资料。
评论登录由 giscus 处理。普通访客在评论区授权;站长在头像菜单里点「连接评论」,由本站服务端接回授权结果。已有评论会话会继续使用。
站长登录不会自动连接评论,评论登录也不授予案例阅读或文章编辑权限。退出站长登录时,本站会一并清除当前浏览器的评论登录。
5. 搜索、评论和浏览统计
搜索
搜索在浏览器里完成。Hugo 构建时生成搜索索引,包含公开页面的标题、所属层级、标签和正文,项目案例不在其中。浏览器下载索引后,查询都在本地进行,不用每输一个字就请求服务器。
评论
评论存放在 GitHub Discussions,通过 giscus 显示在文章页里。评论仓库是公开的,和存放文章的私有仓库分开;发言需要 GitHub 账号。
站长能在文章页管理评论。服务端校验站长会话,删除操作由只安装到评论仓库的专用 GitHub App 调用 Discussions API 完成,写文章的 App 无需增加评论仓库权限。
浏览统计
浏览次数存放在 Cloudflare D1。同一个浏览器保留匿名 Cookie 时,30 分钟内反复打开同一篇文章只算一次;我自己登录后的访问和编辑预览不算。
计数跟着文章的固定编号走,改标题、重新部署都不会清零。这里统计的是去重后的浏览次数,不是访客人数。
6. 这样做的代价
- 发布不是即时的。保存后要等一次构建,读者才能看到新内容。
- 平台依赖比较多。Cloudflare、GitHub、giscus 出问题时,对应功能会受影响;已部署的公开正文由 Cloudflare 提供。平台免费额度有上限,全路径检查还会增加 Functions 请求量,访问量增加时要核算用量。
- 备份要分开做。文章和图片在 Git,评论在讨论区,浏览次数在 D1。Git 历史能找回文章版本,评论和计数要另行备份。
- 权限比较粗。站长只有一个账号,案例共用一个授权码。需要按人授权、单独收回某个人的权限时,就得换账号体系。
目前只有我一个人维护和写作,网站以阅读为主,这些限制还能接受。
评论
使用 GitHub 登录后参与讨论,评论将公开保存在 GitHub。
站长管理删除会同步到 GitHub,无法撤销。
阅读到这里时加载评论。