不要预设困难: 从 Git LFS 到 Cloudflare R2

Web
随笔
一次网站媒体存储迁移复盘: 如何识别错误抽象、验证替代方案,并用 Cloudflare R2 建立独立的媒体工作流。
作者

Pinn Xu

发布于

2026年8月19日

8 min read · 263 EN words · 1790 中文字

1 前言

我的个人网站的图片和视频原本都放在源码仓库的 src 目录中。文件较少时,这种做法简单直接;当媒体资源增长到一两个 GB 后,仓库体积、推送速度和部署时间都开始失控,quarto publish gh-pages 也屡次在最后阶段卡住。

问题并不复杂:媒体文件不该继续和源码一起发布。真正拖慢进度的,是我预设了“对象存储和 CDN 很难配置”,于是我先后尝试了几种看似省事的替代方案。

2 绕路: 继续用 Git 托管媒体

我最先考虑 Git LFS 和 GitHub Releases。两者都能避免把大文件直接写入普通 Git 历史,但它们解决的是代码仓库中的大文件管理,并不是网站的静态资源分发。

为了避免把已有的媒体仓库完整拉到本地,我第一次用 GitHub Codespaces 在云端整理文件,并为整个 video/ 目录启用 LFS。操作体验不错,文件也成功上传了,但 LFS 对象地址并不适合作为稳定、公开的网页媒体源,访问方式和流量模型都与 CDN 不同。

我也试过 GitHub 网页上传和 YouTube 的不公开链接。前者受单文件大小和批量操作限制;后者的上传与嵌入流程较重,播放器样式和地区可用性也不符合需求。

这些尝试让我确认了一点:继续调整 Git 工作流,只是在回避存储架构本身的问题。

3 正解: R2 对象存储与自定义域名

真正开始配置 Cloudflare R2 后,流程比预想中简单:创建 media bucket,按 img/ 和 video/ 组织文件,再将已有域名的 cdn.sample.com 子域名连接到 bucket。网站随后可以直接引用独立的资源地址:

https://cdn.sample.com/img/example.webp
https://cdn.sample.com/video/example.mp4

调整后的结构也更清楚:

源码仓库:Markdown、Quarto 配置、CSS、JavaScript
R2 Bucket:图片、音频、视频
自定义域名:为网站提供稳定的媒体 URL

源码仓库恢复轻量后,构建和部署不再重复搬运大文件;媒体也有了独立于 Git 历史的上传、更新和访问路径。之后我又通过 API 将 R2 接入 PicGo,把上传和生成链接纳入日常写作流程。

4 补齐媒体处理流程

迁移存储只解决了“文件放在哪里”,源文件过大仍会影响上传和加载。在线压缩工具适合偶尔处理单个文件,但常有大小、次数和批量处理限制,也很难稳定控制码率、画质与音量。

我因此重新学习了 Apple Compressor。理解码率、输出格式和音频增益几个核心参数后,便能批量转换格式、预估文件大小并统一音量。专业工具的初始界面更复杂,但对于长期重复的任务,可控性和一致性反而降低了总成本。具体设置另记在 《Mac Compressor 视频压缩与格式转换》 文章中。

最终形成的流程是:

原始媒体 → Compressor 批量处理 → PicGo 上传 R2 → CDN URL 写入文章

5 复盘: 先解决问题,而不是优化 workaround

这次绕路的根因不是工具选错了,而是排查顺序反了。我先假设 CDN 很难配置,再用 Git LFS、Releases 和视频平台逐层回避它。每个局部选择都有理由,组合起来却偏离了最初的问题:网站需要的是媒体存储与分发,不是另一套大文件版本管理方案。

以后遇到类似情况,我会先区分源码管理、文件存储和内容分发,再用最小实验验证为当前问题设计的工具。如果一个 workaround 开始需要新的 workaround,就停下来重新检查问题定义,而不是继续优化临时方案。

这也是我对“不要预设困难”的理解。技术当然可能很难,但应该先打开工具、阅读文档并完成一次低成本验证,再根据事实判断。未经验证的畏难,容易让简单问题长出不必要的复杂度。

6 后记: 重拾“玩电脑”的感觉

R2 配置完成后,我继续研究 API,把媒体库接入 PicGo,并将压缩、上传和生成链接串成一套工作流。打开 Terminal、查文档、调接口、配置域名,再看几个原本独立的工具真正协同起来,我久违地感到了单纯研究电脑的兴奋。

当技术学习长期与课程、项目和求职绑定,很容易认为每项投入都必须对应一个明确产出。但我最喜欢的学习方式一直更直接:先有一件想完成的事,再沿着真实问题把需要的技术逐个学会。

这次也一样。起点只是“网站媒体文件太大”,随后自然涉及 Git LFS、Codespaces、对象存储、CDN、自定义域名、媒体编码和 API。它们不是预先规划的学习路线,而是同一个问题展开后的各个环节。好奇心没有让过程失焦,清楚的问题定义反而给了探索边界。

最终留下的经验很简单:不要给自己预设困难,也不要把精力耗在维护 workaround 上。优先确定真正要解决的问题,然后直接尝试最符合问题本质的解决方案。

回到顶部