一篇文章被发布,通常意味着打开后台、找到编辑器、粘贴正文、上传封面、填写分类,再点击一次发布。
但你现在读到的这篇文章不是这样出现的。它的封面先通过短期凭证直传七牛云,正文随后以 JSON 交给网站,服务端完成 Markdown 渲染、阅读时长计算、标签关联和发布。整个过程没有打开文章编辑页面。

这不是为了少点几次鼠标,而是让个人网站从一个“只能进入后台操作的成品”,变成一个可以被其他工具调用的创作系统。
后台页面只有一扇门
传统 CMS 的能力往往被锁在管理界面里。发布文章只能用浏览器,上传图片只能点击按钮,更新作品只能打开表单。只要离开这个页面,能力就不存在。
问题会在创作链路变长时显现出来:
- 笔记写在 Obsidian,却要手动复制到网站;
- 图片已经在本地整理好,仍要逐张选择上传;
- 作品信息同时存在于项目文档和网站,修改时要维护两份;
- 想做定时发布、批量迁移或自动备份,只能重新模拟人工操作。
一个稳定的 API 相当于为网站增加第二扇门。后台仍然适合人工编辑,而脚本、桌面工具和自动化服务可以走一条结构清晰、可验证的通道。
抽取能力,而不是复制一套后台
最容易犯的错误,是给文章创建一个接口,却在接口控制器里重新写一遍保存逻辑。这样做短期很快,长期一定分叉:后台生成了阅读时长,API 忘了;后台能关联标签,API 保存成了纯文本;后台更新作品媒体,API 留下旧记录。
真正需要抽取的是“发布文章”这件事本身:
输入数据
├─ 校验标题、分类与状态
├─ 生成唯一 slug
├─ 渲染 Markdown
├─ 计算阅读时长
├─ 同步标签与媒体
└─ 在事务中保存
后台表单和 API 只是两个入口,它们应该调用同一份内容服务。这样,无论文章来自浏览器、命令行还是未来的写作客户端,最终规则都一致。
令牌必须比密码更克制
让程序访问网站,不应该把管理员密码交给脚本。个人访问令牌解决的是“谁可以做什么,以及可以做多久”。
例如,一枚用于写作同步的令牌只需要:
articles.manage
article_categories.manage
tags.manage
uploads.create
它不需要管理用户,也不应该读取系统设置。即使令牌意外泄露,影响范围仍被限制在内容发布。服务端只保存令牌的 SHA-256 哈希,明文只在创建时展示一次;不用时可以撤销,彻底不用时可以永久删除。
权限不是为了把界面做复杂,而是让自动化拥有清晰边界。
图片直传,让服务器只负责签字
媒体上传是内容 API 里最容易拖垮服务器的部分。更合适的流程是两步直传:
- 客户端向网站申请一个短期上传凭证;
- 客户端拿着凭证直接把文件传到七牛云;
- 上传成功后,把最终 URL 写入文章或作品。
网站服务器只负责验证令牌、限定文件类型、生成存储路径并签发凭证,不承担大文件中转。这既减少带宽压力,也让网页、桌面应用和命令行共享同一套上传方式。
一个真实的发布请求
这篇文章的核心发布动作可以压缩成一次请求:
curl -X POST "https://www.aora.top/api/v1/articles" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "当个人网站有了 API:把创作从后台页面解放出来",
"content": "Markdown 正文",
"category_id": 1,
"tags": ["API", "自动化", "个人网站"],
"status": 1
}'
请求成功后,网站返回文章 ID、slug、渲染结果和发布时间。调用方不需要理解数据库结构,也不应该直接接触数据库。
接下来可以真正自动化什么
接口存在之后,真正有价值的不是“能用 curl 发文章”,而是把它接入日常工具:
- 在 Obsidian 中完成文章后,一条命令同步封面、正文和标签;
- 将作品目录中的图片按顺序上传,并自动生成作品媒体列表;
- 定期导出文章、作品和设置,形成可迁移的内容备份;
- 从其他平台迁移历史文章,同时保留发布日期和原始 slug;
- 给未来的桌面写作工具或移动端应用提供稳定入口。
个人网站不必变成庞大的平台。它只需要把已有能力整理成边界明确的接口,就能在保持独立的同时,与自己的工具链连接起来。
这篇文章本身就是第一次验证:封面被生成并上传,正文通过接口发布,分类与标签由服务端统一处理。比“接口可以工作”更重要的是,这条路径已经足够清楚,可以被下一段程序重复使用。
