让博客文章携带可下载文件:随文附件功能实现记录
写技术文章时,经常想分享脚本、样例配置或打包好的工具。以前只能把内容整段贴进正文,或者丢到外部网盘——贴正文太占篇幅,网盘要跳转还要担心失效。最理想的形态是像写论文一样:正文里嵌一个下载链接,读者点击即得文件。这篇文章记录这次「随文附件下载」改造的思路、设计与踩坑。
需求背景
博客原本只有文字和图片。遇到要分发文件(示例代码包、配置文件、小型工具)时,没有合适的载体。外部网盘体验差,临时粘贴又不可复用。希望达到的效果是:每篇文章可以有若干附件,附件以超链接形式嵌入正文,点击触发浏览器下载。
设计决策:附件不随整站部署
第一个直觉是:把附件放进站点工程目录,随整站一起发布。但这个博客是静态站,每次发布都会把全站构建产物整体打包上传到服务器。如果把附件放进构建产物,每次部署都要全量搬运这些大文件,越积越大,拖慢部署。
于是改为双通道设计:
- 文章正文、样式、页面等,走原有的整站发布流程;
- 附件文件,走独立的上传通道,直接送到服务器上一个专用目录,不进入站点工程仓库;
- Web 服务器把该专用目录挂载到站点文件路径的某个子路径下,对外提供下载。
这样附件与文章内容解耦:改正文不用重传附件,传新附件也不会触发全站重建。
实现要点
上传脚本。本地一个脚本,从本地配置文件读取服务器地址、登录用户、密钥等连接信息(本地配置不进公开仓库)。执行时把指定文件或目录通过加密通道传送到服务器的附件目录,按文章标识分子目录存放。
失败重试与人工兜底。网络环境不稳定时,上传可能中途失败。脚本内置重试:自动重试数次、每次间隔几秒。多次失败后不再盲目重试,而是非零退出并打印排查指引——连通性检查、磁盘空间检查、手动上传命令。把”修不修”的判断交还给人,而不是静默失败或无限重试。
服务器挂载。附件目录以只读方式挂载进 Web 服务器的容器,映射到站点文件路径下的 /files/ 子路径。浏览器访问该路径时,Web 服务器按静态文件处理,直接返回文件内容并触发下载。文件名即下载后得到的文件名,无需额外路由逻辑。
正文引用。文章里用标准的 markdown 绝对链接指向附件的线上地址,例如「下载说明」。格式简单,任何 markdown 编辑器都能写。
踩坑:只读目录下创建不了挂载点
改造时遇到一个隐蔽问题:站点根目录是以只读方式挂载进容器的,而附件目录要作为它的子目录再挂载一次。容器在只读文件系统里尝试创建新挂载点时报错,直接导致容器启动失败。
排查发现,docker 在挂载嵌套路径时,如果内层挂载点目录还不存在,会尝试自动创建——但这一步发生在只读的根目录里,必然失败。解决方式很朴素:启动容器前,先在服务器上把附件挂载点目录预先建好,再启动容器。目录已存在,嵌套挂载就成功了。
下载限流:防滥用与防带宽占满
附件走公开的静态下载路径,理论上任何人都能访问。为了让功能可以长期稳定对外,在 Web 服务器层给下载路径加了两道限流:
- 请求频率限制。按访问来源 IP 计数:每个 IP 平均每秒最多 5 次下载请求,允许短时间内突发到 20 次,超过的部分直接返回「请求过多」状态码,提示稍后再试。这一道挡住脚本批量刷下载、盗链拉取等滥用。
- 下载速度限制。每个下载连接在文件前 8MB 全速传输,之后限制到每秒 2MB 以内。单个用户即使反复下载,也占不满服务器带宽,不影响其他访客正常浏览。
另外给下载路径关闭了缓存(每次都拿最新文件)——附件更新后,读者重新下载立刻得到新版本,不会被旧缓存误导。两道限流的数值都集中在服务器配置里,方便按实际流量调整。
使用方法
发布带附件的文章,三步即可:
- 本地暂存:把附件放到本地暂存目录,按文章标识分子目录存放(该目录已排除出发布流程);
- 上传:运行上传脚本,传入附件路径和文章标识,脚本自动传到服务器的附件目录并打印线上地址;
- 引用:在文章正文里用下载链接指向该线上地址。
上传脚本会自动重试、失败给出排查指引;若附件含敏感信息(密钥、内网地址、服务器路径),按规则不发到线上,改用占位说明。
配套:mdoc 定制化工具包
这套博客背后还有一套定制化的「文档管理 + 发布流水线」技能(归档修复方案 → 审查 → 生成博客文章 → 自动发布)。为了让它能迁移到另一台机器,我把定制化的技能、子代理和配置打包成了便携工具包,并写了完整的部署说明——详见 mdoc 定制化工具包部署指南。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!













