跳至内容

ORTHANT 技术架构

ORTHANT 的技术选型和运行方式。

  • 系统架构
  • Hugo
  • Cloudflare Pages
  • GitHub App
  • 工程实践

ORTHANT 用 Hugo 生成网页,部署在 Cloudflare Pages,Markdown 原稿保存在 GitHub。

博客由我个人维护,选 Cloudflare Pages 是为了省去服务器运维。

读者打开页面要快,评论和统计出问题也不该耽误阅读。所以正文在发布时就生成好,评论、计数这些功能单独加载。

1. 整体结构

ORTHANT 架构流程图:文章发布、正文访问、评论与浏览统计

部分工具用途
内容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。

现在直接在文章页编辑:登录后点「编辑本文」,改完点「保存并发布」。保存流程如下:

  1. 服务端核对站长账号和仓库写权限。
  2. 检查文章版本。如果文章在编辑期间被别处修改,本次保存会停止,并提示重新打开对比。
  3. 正文和本次新插入的图片放进同一次 Git 提交。
  4. Cloudflare 收到主分支的新提交,用 Hugo 重新生成整站并部署。
  5. 浏览器对照线上构建清单,确认本次文章版本已部署,显示「文章已上线」。

提交成功和文章上线是两回事: 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。

阅读到这里时加载评论。