‹ 返回首页技术

第一章记录这个空间怎样长大,第二章拆开它的实现:静态页面与动态服务如何分工,网页写作怎样走到真正上线,邮件、数据、性能与私密内容又各自需要守住什么边界。

2026年10月25日·26 分钟阅读·阅读 …

文章目录
  1. 一、先回答那个问题:它到底是不是静态网站
  2. 二、网页写文章的背后,其实仍然是一份 Markdown
  3. 三、发布不是一个按钮,而是一条有中间状态的链
  4. 进度条应该跟着任务,而不是跟着页面
  5. 旧任务也不能随便覆盖新版本
  6. 四、邮件不是发布按钮后面的一个附带请求
  7. “已发送”也需要解释
  8. 幂等,不能只写一个漂亮的词
  9. 免费额度不是一个只供展示的数字
  10. 五、数据一多,真正的问题不是列表能不能再拉长一点
  11. 原始数据和检索视图要分开
  12. 每个异步请求,都可能回来得太晚
  13. 六、前台性能:要先分清到底是谁在忙
  14. 动效要有开始,也要有结束
  15. 按需加载比把一切写进公共入口更重要
  16. 七、私密文章:隐藏正文,不等于隐藏一切
  17. 附件需要另外处理
  18. 私密评论不是端到端加密聊天
  19. 八、备份:有一个压缩包,还远远不够
  20. 九、一个很小的编号问题,为什么也值得认真做
  21. 十、做完这些,我没有更想把它做成一个大平台
  22. 下一章:让这个空间真正活起来
  23. 技术参考
  24. 开源项目与第三方组件声明
  25. Astro 及官方集成
  26. Marked
  27. Turndown
  28. js-yaml
  29. resvg-js
  30. Node.js
  31. Python
  32. Git
  33. Cloudflare
  34. GitHub 与 GitHub Actions
  35. Resend
  36. 设计参考
  37. 项目自身与 AI 协作

在第一章里,我记录了这个空间从一个念头,慢慢变成一个真正的网站的过程。

那一章没有展开技术。因为相比用了什么框架,我更想先留下:为什么会开始,又为什么在一次次觉得“不对劲”以后,还愿意继续改。

这一章,换一个角度。

如果把现在的页面拆开,文字怎样到达读者的屏幕?点击发布以后发生了什么?为什么有时后台看起来已经成功,前台却还是旧文章?一个看上去只是几块颜色的背景,为什么会让电脑风扇转起来?

这些问题,比列出一串技术栈更能说明这个项目。

Henry 的空间没有采用一套一开始就设计完整的架构。它是在具体的问题里,逐渐学会把内容、状态、数据和责任分开。

以下以截至 2026 年 10 月 24 日的项目实现为准。文中的流程是便于理解的简化表达,不是完整部署教程,也不意味着所有场景都已经验证。

一、先回答那个问题:它到底是不是静态网站

如果只看公开文章和主要页面,是。

目前的前台由 Astro 在构建时生成 HTML,再交给 Cloudflare Pages 分发。读者打开一篇文章,不需要先等待一台应用服务器查询数据库、临时拼出正文。

但如果看整个网站,只说“静态网站”又不完整。

评论需要保存,订阅需要验证邮箱,后台需要读取和修改文章,通知需要在合适的时候发送。这些事情不是把几个 HTML 文件放上去就会自然发生的。

所以,更准确的描述是:

一个静态优先的内容前台,加上一组负责互动和管理的动态服务。

大致分工如下:

部分

使用的东西

在这个空间里负责什么

内容和页面

Astro、Markdown

把文章与站点信息生成可阅读的静态页面

静态分发

Cloudflare Pages

承载页面、样式、脚本与公开资源

互动和管理

Cloudflare Workers

处理评论、订阅、统计、后台操作和任务协调

业务记录

Cloudflare KV

保存评论、订阅关系、通知及任务状态等记录

管理检索

可选 D1 投影

为后台筛选、排序和分页提供可重建的查询视图

版本和发布

GitHub、GitHub Actions

保存内容历史,测试、构建并部署对应版本

邮件

Resend

接收站点发出的验证与通知请求

这不是“静态”和“动态”之间选一个,而是按事情的性质分配工作。

文章正文更新频率不高,适合提前生成;评论提交是一个实时动作,交给接口处理;稍后阅读和阅读历史只需要服务当前设备,就留在浏览器本机,不额外制造一套云端账号系统。

这样的分工也有代价。

我在后台改完一段首页文字,并不会立刻改变所有人看到的页面。它仍然要经过提交、构建和部署。网站也没有因为不需要自己维护传统服务器,就摆脱了服务故障、额度限制和运维责任。

静态优先减少了一类复杂度,但没有让复杂度消失。

二、网页写文章的背后,其实仍然是一份 Markdown

最早,我只需要“能把文章放上去”。

后来,要求逐渐变成了:能在网页里写,能预览,能插图片,能保存没有写完的内容,最好不必每次都去操作源码仓库。

这里没有把文章整体搬进一个新数据库。当前的文章来源仍然是仓库中的 Markdown 文件。

网页编辑器负责把写作操作转换成文章内容,管理 API 负责在获得授权以后,把它写入 GitHub。富文本与 Markdown 两种模式之间,使用 Marked 和 Turndown 衔接。

一篇文章除正文之外,还带有一段元信息:

---
title: "一篇还没有写完的文章"
description: "先把问题记下来,再慢慢整理。"
pubDate: 2026-10-24
category: "技术"
tags: ["实践", "记录"]
cover: c3
draft: true
private: false
---

这个例子中的 draft: true,不是给标题旁边画一个“草稿”标签。

它会影响构建时的内容筛选:文章不能因为已经存在于仓库,就自动进入公开文章列表、搜索、订阅源或正文路由。

这里必须分清三个东西:

  • 本机临时草稿:用于恢复尚未保存的编辑内容,不能代替持久备份。
  • 已保存的文章草稿:已经写入仓库,但仍未公开。
  • 公开文章:完成发布流程后,可以在前台阅读的版本。

如果把它们都显示成“保存成功”,操作起来很轻松,出了问题却很难知道到底丢在哪一步。

保留 Markdown 和 Git 历史,对我还有一个实际意义:文章不只存在于某个编辑器界面里。即使以后更换前台,内容本身仍然有相对清楚的组织方式和版本记录。

但这不等于编辑器可以随便转换任何内容。富文本、代码块、视频和自定义附件都有各自的结构;两种模式切换后,还需要核对有没有把不认识的内容丢掉。界面上“看起来差不多”,并不是内容完整的证明。

三、发布不是一个按钮,而是一条有中间状态的链

这个项目里反复出现过的一类问题,是“后台说成功,但实际还没有成功”。

我点击发布,文章列表马上显示已发布;进度条还在走,前台却找不到文章。切换页面再回来,进度没了,留下来的那个“已发布”反而更像真的。

原因不是进度条不够漂亮,而是把不同阶段的成功,混成了同一种成功。

当前的主要链路,可以简化为:

编辑器提交
    ↓
文章写入 GitHub,获得提交 SHA
    ↓
对应的 GitHub Actions 运行测试与构建
    ↓
Cloudflare Pages 部署该版本
    ↓
确认对应版本成功上线
    ↓
如本次选择通知,再继续处理订阅邮件

这里的提交 SHA,可以理解为这次版本的明确身份证。

后台需要问的不是“仓库最近有没有一次成功构建”,而是:

我刚才提交的那个版本,有没有完成它自己的发布?

否则,上一轮的成功就可能被拿来解释这一轮尚未完成的任务。

同样,文件上传完成,也不能直接推出站点部署成功;服务商接受了部署请求,也不能推出读者已经能读到对应内容。

现在,发布状态围绕具体提交核对。查询失败、找不到对应运行、构建仍在进行,都不应该被一个超时定时器自动翻译成“已上线”。

进度条应该跟着任务,而不是跟着页面

页面可以关闭,发布任务不应该因此被当成不存在。

目前,文章的发布任务有本机恢复状态,近期云端发布记录也可以供后台重新核对。切换页面或换一个设备,不必只靠之前那一段动画来猜测发生了什么。

进度条放在对应文章行下面,也是同一个思路:它属于这篇文章的这次发布,不属于某个全局“正在忙”的装饰区。

有些阶段能确定,有些阶段只有状态、没有精确百分比。后者就应该诚实显示“构建中”或者“等待核对”,而不是让一个数字按时间匀速长到 100%。

旧任务也不能随便覆盖新版本

部署排队还会带来另一个问题:较早提交的构建,可能在较晚的时候才完成。

当前流程在部署前会重新核对远程主分支。已经被后续版本替代的构建,不应再覆盖生产页面。

这同时意味着,过期构建被拒绝,并不等于每一个与它相关的通知任务都自动解决。通知仍然需要自己的状态核对,不能只看“网站现在能打开”。

我后来越来越觉得,好的发布界面不是永远报喜,而是能把已保存、构建中、上线成功、失败和待核对讲清楚。

四、邮件不是发布按钮后面的一个附带请求

评论、回复、订阅和友链陆续加进来以后,邮件从一个小功能变成了另一条完整流程。

其中最直观的问题是:如果文章还没上线,订阅者先收到了邮件,点击进去却是不存在的页面,这封邮件虽然“发成功了”,产品上却是失败的。

所以,当前文章订阅通知的顺序是:先保存通知意图,等待对应部署成功,再进入发送处理。

不是由浏览器在保存文章之后,临时补发一个请求。否则页面一关,后半段事情可能就没有了。

评论审核和回复通知,则需要记住这次通知对应的具体记录、模板和正文。重试不应该悄悄换一封信,也不应该在评论已经删除或状态改变之后,继续发送过时内容。

“已发送”也需要解释

对当前网站来说,邮件状态里的“已发送”,表示邮件服务商返回了成功回执。

它不等于收件人一定看到了,也不等于邮件必然进入收件箱而非垃圾箱。目前还没有接入完整的送达与退信 webhook,不能把尚未接入的能力写成已经存在。

同样,失败重试也不能无限进行。

对于超时或暂时限流,可以有界重试;对于永久错误、过旧任务、超出尝试次数或者中途中断的群发,就应当停下来,留下人工核对入口。

幂等,不能只写一个漂亮的词

“幂等”在这里可以粗略理解为:同一件事重复请求,尽量不要造成重复结果。

当前实现会让同一邮件任务复用稳定的请求标识和相同内容,以减少重试导致的重复发送。但 KV 不是一个可以提供跨实例强一致任务锁的系统;邮件服务商的幂等保护本身也有适用范围和时间边界。

因此,我不会把这里描述成“无论怎样出错都绝不重复发送”。

能做的保护需要做,不能保证的部分也需要写出来。

免费额度不是一个只供展示的数字

一封评论通知很小,但验证、审核、回复和群发叠加起来,就会成为真实的使用量。

后台因此需要额度明细、重置时间和提醒入口,也要为额度提醒预留发送空间,避免最后一封普通通知把提醒本身的机会用掉。

任务检查也不是越勤越好。当前的定时处理会区分空闲与活跃状态,降低空队列反复扫描造成的消耗;有新任务时再提高处理频率。

这属于在免费优先前提下控制工作量,不是“从此没有额度问题”。平台配额和处理延迟仍然存在,代码里的项目预算也不等于服务商承诺的免费容量。

五、数据一多,真正的问题不是列表能不能再拉长一点

评论、订阅者和友链只有几条时,把全部记录读出来,在浏览器里搜索和分页,似乎很方便。

但数据一多,问题会一起出现:

每次打开都要读很多数据;搜索结果可能只覆盖当前页;筛选后的数量不是真实总数;某一批读取失败,页面却显示“暂无记录”。

这里最需要改变的,不是把每页从十条改成五十条,而是数据读取方式。

当前后台逐渐采用服务端筛选、分页和完整索引检查。冷索引还没建立完成时,返回的是进度,不是把读到的一小部分包装成全量结果。

“没有记录”和“没有读成功”,必须是两个状态。

原始数据和检索视图要分开

现在评论、订阅等业务原记录仍在 KV。D1 在这里承担的是可选的管理检索投影,而不是把原业务记录整体迁走。

可以把它理解成一本用于找东西的目录:

  • 原始评论和订阅关系是需要保留的记录。
  • 检索投影是为了方便搜索、排序和分页生成的视图。
  • 目录坏了,可以按规则重新建立;不能因为目录暂时找不到,就把原记录视为不存在。

这也解释了为什么一些敏感令牌不应该进入检索投影。管理列表需要展示哪些信息,与通知链接或私密访问需要哪些凭证,不是同一件事。

缓存同样需要这层区分。它可以提高读取效率,却不能成为新的、不知从哪里来的事实来源。

当前实现会检查投影版本和期限,修改后使相关视图失效,必要时回到原始记录重新核对。服务故障或超出既定预算时,也需要明确失败或按已定义的路径回退。

这里没有跨 KV 和 D1 的原子事务,也没有承诺所有节点瞬间读到同一个结果。

对我来说,重要的是承认这些限制,再设计冲突、重建和刷新行为,而不是用“加了数据库”四个字跳过它们。

每个异步请求,都可能回来得太晚

后台还有一类不太显眼的错误:我已经换了筛选条件,旧请求才返回,直接把新列表覆盖了。

同样的事情也会发生在编辑器里。退出、切页之后,先前的文章读取或解密结果不应该突然把旧界面重新打开。

处理这类问题,需要取消不再需要的请求,或核对请求属于哪一次操作;返回得晚,不代表它仍然有权更新界面。

这不是增加一个加载图标能解决的。

六、前台性能:要先分清到底是谁在忙

这个空间的性能问题,有两种容易被混在一起的表现。

一种是页面还没加载出来,另一种是页面已经打开,电脑却持续发热。

前者可能涉及 DNS、网络链路、资源来源、缓存和服务响应;后者则需要检查动画、绘制、脚本和后台任务。没有实际测量,不能一概说是 Cloudflare 的问题,或者说是访问者电脑不行。

我最早特别想要一个有呼吸感的背景。

颜色要更明显,移动要更自然,轨迹不要循环得太死,色块边缘还不能有圆点、色环或者三块透明圆形的感觉。

视觉上的每一个小要求,都可能增加持续绘制的工作。而网站打开以后,大部分时间其实只是有人在看文字。

后来形成的方向,不是彻底不要动画,而是把它从“永远在表演”,改成“在有意义的时候回应”。

动效要有开始,也要有结束

入场动效可以短暂出现,内容位置要稳定;按钮可以对点击有轻微反馈,但不需要所有卡片一起平移;页面离开、隐藏或功能不再使用时,相应的观察和轮询应该停止。

还要照顾减少动态效果的设备偏好。动画不能成为内容可读的前提:脚本未运行或用户减少动效时,正文也不应该一直透明。

首页刷新时那种“抽一下”的感觉,就提醒了我:动画不是加上过渡时间就算完成。初始布局、字体、最终位置和播放时机一起参与了结果。

按需加载比把一切写进公共入口更重要

普通读者没有打开后台,就不应该下载完整编辑器;没有打开某个复杂功能,也不必先准备它的全部逻辑。

现在项目把一些前台交互、后台模块和私密内容处理拆开,按实际需要加载,并给脚本、样式和媒体设置项目级预算。

预算的意义,不是证明某个字节数具有普遍正确性,而是让后续每次加功能都看见代价。

媒体也一样。视频、音频和私密附件应该由读者主动使用时再处理,而不是因为它们存在于页面,就一开始全部下载、解密或播放。

这些改动有构建和隔离浏览器检查作为依据,但它们不能替代所有手机、平板和长时间功耗测试。我不想把“这一次没有发现问题”写成“所有设备都不会卡”。

七、私密文章:隐藏正文,不等于隐藏一切

私密文章最初的要求很直接:不输入密码,就不能看到正文。

要做到这一点,不能只在页面上盖一个密码框,然后把明文藏在下方。

当前实现是在浏览器中使用 PBKDF2-SHA256 派生密钥,再用 AES-GCM 加密正文。发布文件保留密文,访问者在本机输入密码以后解密;文章密码不作为明文上传给站点接口。

但我必须同时写清楚,它保护的是什么:

正文是私密的,标题、摘要、日期、分类、标签和封面仍然是公开信息。

如果不想让某个信息公开,就不能把它写进摘要,指望正文密码替自己保护。

密码强度也重要。静态密文可以被下载,弱密码存在离线猜测风险。给页面设置 noindex 只能表达不希望被搜索引擎收录,不是访问控制,更不能代替加密。

附件需要另外处理

把文章正文加密,并不会让其中原本公开的图片和文件 URL 自动变成私密。

后来增加的私密附件,会先在本机使用随机独立的 AES-256-GCM 密钥加密,只上传密文。解密密钥、文件名和媒体类型放进加密正文,而不是暴露在公开元信息里。

当前单件附件上限为 8 MiB。这是现有实现边界,不是说任意大小的文件都适合这种方式。

读者解锁正文以后,仍然需要主动点击才下载和解密附件;重锁和离页时清理播放器与本机临时链接。

但是,已经公开过的旧图片、外链和他人下载的副本,不会因此被收回。已经获准阅读的人,也仍然可以复制、截图或主动下载。

私密评论不是端到端加密聊天

私密文章解锁后的评论,需要把访问凭证与对应文章和线程关联,不能把私密讨论混进公开列表。

不过,评论和邮件通知仍然经过服务端,作者也需要在后台管理。它不是只有通信双方能够解密的端到端加密系统。

历史评论缺少归属凭证时,更不能为了“恢复显示”就自动猜测绑定。当前有单条核对工具,但真正的历史内容处理仍需要作者确认。

把边界说明白,本身就是安全设计的一部分。

八、备份:有一个压缩包,还远远不够

随着评论、订阅和邮件任务出现,Git 已经不能单独代表整个网站的数据。

源码和文章可以在仓库里,但业务记录、运行配置以及恢复时需要注意的任务状态,并不会因为仓库还在就全部回来。

当前的备份流程会导出相关数据和配置,做完整性核验并加密保存。仓库中保留备份公钥,私钥需要另行妥善保管。

但这里至少有四个不同问题:

  1. 备份工作流有没有运行成功?
  2. 加密文件现在还在不在,能不能下载和解密?
  3. 内容是否完整,记录及必要元数据有没有丢?
  4. 把它恢复到隔离环境以后,结果是否符合预期?

前一个成功,不能代替后一个。

这个项目已经做过离线核验和全新隔离 KV 的恢复演练,检查记录值、元数据和到期信息,结束后清理临时资源。

它不是把备份写回正在使用的生产空间,也不意味着任何时候都可以无风险覆盖生产数据。

尤其是通知任务:恢复一批业务记录,不应该顺手把过期群发、缓存和旧运行状态一起重新激活。恢复工具需要知道哪些是应保留的原数据,哪些是应该隔离或重新建立的运行态。

同样,代码回滚和数据恢复是两件事。

把页面切回前一个版本,可能修好界面;它不会自动撤回一封已经发出的邮件,也不会自动修复之前已经修改的记录。

我现在理解的“方便回滚”,不是有一个按钮,而是知道回滚什么、不回滚什么,以及怎样证明没有伤到其他东西。

九、一个很小的编号问题,为什么也值得认真做

最近,文章封面编号又改了一次。

原来它跟着当前页面的排列位置走。看全部文章是一种号码,筛选分类后又变成另一种;同一篇文章,在不同位置仿佛有不同身份。

视觉上只是左上角的几个数字,背后却是“位置”和“身份”混在了一起。

现在,编号归属于文章,而不是归属于这一页列表的第几行。

初始历史文章按照现有文章日期、必要的 Git 历史顺序和稳定标识固定下来;以后的新文章按主分支首次非草稿的提交次序接续。删除不回收旧号,同一文章改标题、改日期或重新出现,不因为列表变化重新编号。

草稿不占号,也不需要作者自己填一个数字。

这里还要保留一点诚实:早期文章标注日期和 Git 历史,并不等于掌握每篇旧文最初在 Cloudflare 上线的精确时刻。初始编号采用的是项目能核实的历史规则,不是假装补回不存在的日志。

它给我的启发是:有些看起来只属于 UI 的问题,其实在提醒我们,数据模型还没有想清楚。

十、做完这些,我没有更想把它做成一个大平台

写到这里,技术名词已经不少。

但这些选择的目标,并不是让一个个人博客看起来有多复杂。

我不需要在每次阅读前让访问者注册账号;稍后阅读和历史留在本机,就意味着换设备不会自动同步。页面静态生成,就要接受内容更新需要构建。选择免费优先,就要接受额度预算、等待和有边界的降级。

也有一些事情还没有被做成结论。

历史私密评论与旧公开资源需要继续由作者核对;后台会话和凭据的后续调整是独立工作;真实设备的长期功耗、跨浏览器细节和邮件实际送达,不能因为已有测试就视为永远没问题。

这些不是文章最后需要遮住的部分,而是这个系统当前形状的一部分。

如果第一章讲的是“为什么愿意继续做”,这一章讲的就是:

想让一个网站长期存在,不能只把成功路径做出来。还要让失败可见、状态可信、数据有归属,并为下一次修改留下余地。

这也是我在 AI 辅助开发里逐渐形成的感受。

把一个想法变成界面,确实变快了。但界面背后的事实,不会因为生成得快就自动成立。它仍然需要读代码、查文档、看实际结果,区分已经实现和还没有验证。

我不想把 Henry 的空间包装成一份标准答案。

它只是我当前用来写作、记录项目、与读者交流的一套具体选择。规模改变、需求改变以后,有些选择还会再改。

只要内容没有被工具绑住,读者没有被多余的效果打扰,下一次发布能知道自己进行到哪里,出了问题还能找到恢复的路,这一阶段的技术工作就有了意义。

第一章里,我写的是从想要一个网站,到愿意对它负责。

第二章走到这里,我想把“负责”再落到具体一点:

不要让页面替系统承诺它还做不到的事。

保持好奇,無限进步。

下一章:让这个空间真正活起来

系统逐渐稳定以后,我又回到了页面本身:一轮依据设计工具展开、却被推翻的改版;从“看不出区别”到终于有了活感的动效;以及那些功能已经实现,体验却仍然不对的细节。

如果这一章关注的是怎样让网站值得长期维护,那么下一章谈的,就是怎样让这个已经能用的空间,更像我愿意停留的地方。

继续阅读:Henry 的空间 · 第三章:从能用到好用,让空间真正活起来


技术参考

本文关于本站的描述,以项目当前源码和实际核验记录为依据;以下官方资料用于说明相关技术的基础行为,不代表服务商为本站实现作出保证。

开源项目与第三方组件声明

以下按项目分别列出原作者、上游出处与授权信息。这里说明的是 Henry 的空间实际使用的基础项目与服务,不把它们的能力或代码归为本站原创。

Astro 及官方集成

  • 项目:Astro、@astrojs/rss、@astrojs/sitemap
  • 原作者与维护者:Fred K. Schott、Astro 团队及贡献者
  • 上游仓库:withastro/astro
  • 许可证:MIT License
  • 用途:页面生成、内容集合、RSS 与站点地图等基础能力。

Marked

  • 项目:Marked
  • 原作者与维护者:Christopher Jeffrey、MarkedJS 团队与贡献者
  • 上游仓库:markedjs/marked
  • 许可证:MIT License 及随附声明
  • 用途:后台 Markdown 解析与文章预览。

Turndown

  • 项目:Turndown
  • 原作者与维护者:Dom Christie 与贡献者
  • 上游仓库:mixmark-io/turndown
  • 许可证:MIT License
  • 用途:将可视化编辑内容转换为 Markdown,衔接两种书写方式。

js-yaml

  • 项目:js-yaml
  • 原作者与维护者:Vitaly Puzrin、Nodeca 及贡献者
  • 上游仓库:nodeca/js-yaml
  • 许可证:MIT License
  • 用途:构建链中解析文章元信息,支持文章固定编号等逻辑。

resvg-js

  • 项目:@resvg/resvg-js
  • 维护者:resvg-js 项目维护者与贡献者
  • 上游仓库:thx/resvg-js,原 yisibl/resvg-js 地址现跳转至该仓库
  • 许可证:MPL-2.0
  • 用途:将 SVG 渲染为文章分享图片等位图产物。

Node.js

  • 项目:Node.js
  • 维护者:Node.js 项目维护者与贡献者
  • 官网:nodejs.org
  • 许可证:核心采用 MIT 许可证;第三方组件另有随附声明,见官方 LICENSE
  • 用途:运行项目构建、测试与相关脚本。

Python

  • 项目:Python
  • 维护者:Python Software Foundation 与贡献者
  • 官网:python.org
  • 许可证:主要采用 PSF License Version 2
  • 用途:部署保护、备份核验与恢复相关自动化。

Git

  • 项目:Git
  • 维护者:Git 项目维护者与贡献者
  • 官网:git-scm.com
  • 许可证:GPL-2.0
  • 用途:保存文章与代码版本,提供历史追溯依据。

构建链还包含其他间接依赖。具体版本、版权和授权要求,以锁文件、实际使用版本及各组件随附许可证为准;这份说明不代替完整的软件物料清单,也不把不同组件合并成同一种许可证。

Cloudflare

  • 服务:Cloudflare
  • 提供方:Cloudflare
  • 官网:cloudflare.com
  • 使用能力:Pages、Workers、Workers KV、D1、Turnstile 及相关网络与站点服务。
  • 说明:托管与安全服务,不是本站原创的开源组件;额度、费用和使用条件以实际账户及官方规则为准。

GitHub 与 GitHub Actions

  • 服务:GitHub、GitHub Actions
  • 提供方:GitHub
  • 官方说明:GitHub Actions 文档
  • 用途:仓库、内容历史、自动测试与部署流程。
  • 说明:服务、运行环境和所调用的 Action 是不同层次;具体 Action 的授权以其各自仓库和许可证为准。

Resend

  • 服务:Resend
  • 提供方:Resend
  • 官方说明:Resend 文档
  • 用途:订阅验证、评论、回复与其他站点通知邮件。
  • 说明:第三方邮件服务;服务商接受、实际送达与收件人阅读不是同一状态。

设计参考

视觉方向参考 Apple 产品中克制的排版、留白与交互秩序。Henry 的空间不是 Apple 官方产品,与 Apple 不存在官方隶属或背书关系。相关商标与权利归各自权利人所有。

项目自身与 AI 协作

Henry 的空间由 Henry 发起并持续维护,开发与本文整理过程中借助 OpenAI Codex 辅助。AI 辅助不改变第三方组件的原有作者归属和许可证要求,也不能代替对实际代码与运行结果的核对。

截至本文整理时,源码仓库为私有,尚未为整个项目额外声明开源许可证。使用开源组件,不等于整站源码、文章和站点素材已经开放再分发。

本文不公开后台密码、访问令牌、备份密钥、订阅者邮箱或访客个人数据,也不要求读者向任何人提供这些信息。


项目与本文署名:Henry。记录截至 2026 年 10 月 24 日。

第一章:Henry 的空间 · 第一章:从一个念头到一个真正的网站

H
Henry

记录技术实践、设计观察与生活里的慢思考。

关于作者
DISCUSSION

评论 0

留下想法或补充。评论经审核后会显示在这里。

正在读取评论…