附件与限额:四十六个文件、三百一十二兆与五个跳过

任务和评论都导进来了,四十六个附件却全变成红叉。本文拆解下载重传、保留外链、明确跳过三种策略,给出单文件五十兆、单次五百兆与八类白名单的限额表,逐条复算三百一十二兆的配额占用与五个跳过的原因,并交付一份客户可执行的三列失败清单。

任务搬得过来,不等于文件搬得过来;附件是迁移里唯一按兆算、也最容易承诺过头的部分。

一、任务都在,附件全是红叉

陈砚秋把最后一批任务导进客户工作区时,列表、评论、负责人、日期都对得上。客户回了一句「看起来不错」,十分钟后又发来一张截图:任务详情里二十几个附件图标全变成红叉,点开是 404。

以下情境为教学假设,人物、引语和数字不代表经核实的真实案例。

他第一反应是对象存储的权限没开。查了十分钟,发现不是:文件根本没上传,数据库里只有源系统留下的 URL,导入器把 URL 当成附件记录写了进去,却没有把字节搬过来。

这是附件迁移最典型的误会。「附件已导入」在两个系统里是两件事:源系统说「这个任务有一个文件」,目标系统要的是「这个文件在我的桶里,键是什么,谁能读」。前者是元数据,后者是字节;只搬前者,界面上就会出现一排红叉。

客户的原始系统导出的是一个压缩包,里面 46 个文件,合计 312 MB。他先按「全部原样搬」答应下来,真正开始传才发现三件事:单个文件有上限、单次导入有总量上限、不是所有类型都允许进工作区。

这三件事没有一条写在客户的导出说明里,也没有一条能靠读 CSV 推出来。它们是你产品的限额,必须在导入开始前讲清楚,否则客户理解的「搬过来」和你实现的「搬过来」不是同一个东西。

这一篇讲这一次附件迁移:46 个文件、312 MB、41 个成功、5 个跳过,以及为什么「跳过」必须是一个明确的产品动作,而不是一个被吞掉的异常。

二、三种策略:下载重传、保留外链、明确跳过

附件进不来时,产品通常只有三种处理方式,选哪种取决于文件归谁、还能不能访问、以及客户是否接受链接而不是副本。

策略做法适用情形主要风险
下载重传从源 URL 取字节,写进自己的存储源链接可公开访问、文件在限额内下载超时、类型不符、重复占用配额
保留外链只存源 URL,点击时跳转源系统仍在用、客户接受链接链接失效、权限变化、无法审计
明确跳过不导入,写进失败清单并说明原因超限、类型不允许、源文件已丢客户以为已迁移,实际缺文件

下载重传是最容易承诺、也最容易在细节上翻车的一种。它要处理的不只是 GET 一个 URL:源站可能要求签名、可能限速、可能返回一个 302 到登录页,而你的下载器会把登录页的 HTML 当成文件存下来,得到一个 200 但内容是 <html> 的「成功」。

保留外链看起来最省事,实际上是把风险推迟。外链依赖源系统的账号和权限,客户一旦停掉旧账号,附件就集体失效;更麻烦的是,外链内容不在你的备份里,恢复时也恢复不出来。

明确跳过是三种里最需要产品设计的。跳过不是「失败后什么都不做」,而是「判断它不该进、告诉客户为什么、给一个替代动作」。没有这三步,跳过在客户眼里就是丢失。

他最后把三种策略组合使用:46 个文件里,能下载的走重传,源系统还在合同期内的少量外链保留,超限和类型不允许的明确跳过。组合的前提是每个文件都有一条决定记录,而不是按批量一刀切。

组合策略的代价是判断成本。每多一种策略,就多一条分支、多一个失败原因、多一段要向客户解释的话。如果 46 个文件里只有 1 个需要外链,那为它单独做一条链路的维护成本,可能高于直接告诉客户「这个文件请手工上传」。

他的取舍是:默认重传,外链只给「源文件大于单文件上限但客户明确还要」的个例,其余一律跳过并写清原因。这条规则不完美,但它能被解释,也能被复算。

三、限额表:单文件五十兆、单次五百兆与八类白名单

限额不是拍脑袋的数字,它同时受存储成本、请求超时、病毒扫描和后续备份影响。他给自己产品定的三条线是:单文件 50 MB、单次导入 500 MB、8 类白名单。

限额项取值判定时点超限后的动作
单文件大小50 MB下载响应头与落盘前各查一次跳过,记 file_too_large
单次导入总量500 MB批次开始时预占,结束释放拒绝整批,提示拆分
文件类型8 类白名单扩展名与 MIME 双查跳过,记 unsupported_type

8 类白名单的写法要比「允许图片和文档」具体得多。他的清单是:PDF、PNG、JPEG、GIF、WebP、纯文本、CSV、ZIP;每一类同时校验扩展名与 MIME,两者不一致时以更保守的一方为准。

双查的理由很实际:扩展名可以改,MIME 可以由客户端伪造,单看任何一个都会放过伪装文件。反过来,双查也会误杀——某些系统把 CSV 报成 application/octet-stream,把旧版 Word 报成 application/msword,这些都要在失败清单里给出可读的原因,而不是一句「类型错误」。

上传接口的报错也要能对上限额。他早期只返回一个 400,客户拿到的信息是「导入失败」,既不知道是哪个文件、也不知道该改什么。后来改成结构化错误:

413 file_too_large       report-2024.pdf   超过单文件 50 MB
415 unsupported_type     design.ai         不在 8 类白名单
409 quota_exceeded       本批合计           超过单次 500 MB

这三个错误码对应三种完全不同的客户动作:压缩、转格式、拆批。错误码不解释,客户就只能整批重来。

限额还要写进导入前的说明里,而不是等失败才出现。他在导入向导第一步放了一张表,写明单文件、单次总量、允许类型;客户勾选「我知道了」之后才能继续。这一步让后面的失败清单短了很多。

单次 500 MB 的预占也有讲究。不能等文件一个个传完再算总量,否则传到后面才发现超了,前面已经成功的都要回滚;正确做法是批次开始时按清单里的 Content-Length 预占,传完一个释放差额。

预占的代价是要处理「声明的长度和实际字节不一致」。有的源站返回压缩后的长度,有的返回未知长度,有的在中途断流。他的兜底是:声明长度缺失时按单文件上限预占,实际落盘后再校正;校正失败就把整个批次标成待复核,不自动继续。

四、五个跳过的账与附件这一段有多贵

这次 46 个文件里,41 个成功、5 个跳过;成功的 287 MB,跳过的 25 MB,加起来正好 312 MB。跳过率 10.9% 不算高,但每一个跳过都要有原因、有建议、有客户确认。

文件名原因建议
report-2024.pdf超过单文件 50 MB压缩后重传,或拆成两份
backup-full.zip超过单文件 50 MB只传需要的子目录
raw-data.csv超过单文件 50 MB按年份拆分后重传
design.ai类型不在 8 类白名单导出为 PDF 或 PNG 后重传
old-plan.psd类型不在 8 类白名单导出为 PNG 后重传

三列看起来简单,写起来要克制:原因必须来自系统判定,不能写「格式不支持」这种客户无法行动的句子;建议必须是客户在十分钟内能做完的动作,不能写「联系管理员」。

配额占用是另一个容易被忽略的账。312 MB 落在 500 MB 的单次额度里是 62.4%,看起来还有余量;但配额不是按次清零的,它和客户已有附件共享同一个上限,真实可用空间要用「当前占用 + 本次 312 MB」再和 500 MB 比。

这也是「跳过」在账上反而有利的一面:5 个文件 25 MB 没有进来,配额少占了 25 MB,客户后续上传的余量更大。代价是客户拿到的不是完整副本,所以跳过清单必须随迁移报告一起交付,而不是留在你的日志里。

成功文件的平均大小是 7.0 MB,这个数字用来估下一批的耗时比用来做承诺有用。附件迁移的时间主要花在下载和扫描,不花在写数据库;46 个文件里 41 个成功,意味着绝大多数请求都走完了完整链路,任何一个环节超时都会把成功数拉低。

附件是导入里最贵的一段,贵不在存储费,而在「每个文件都要单独判断」。任务行可以批量映射,附件不行:每个文件有自己的大小、类型、源地址和权限,任何一个不同,处理分支就不同。这些文件的最终去向,和导出包里的 attachments.zip 是同一份清单,见导出与退出:九十六秒、四件套与「走得掉」的承诺 。

复算:文件数、字节数、跳过率与配额占用各算一遍,注意 MB 与配额的对应关系。

46 个文件 312 MB;成功 41 个 287 MB、跳过 5 个 25 MB
287 + 25 = 312 MB;跳过率 5 ÷ 46 = 10.9%
跳过原因:>50 MB 3 个 + 类型不允许 2 个
配额占用 312 ÷ 500 = 62.4%
成功文件平均 287 ÷ 41 = 7.0 MB

边界要写清楚:这 46 个文件只代表一次迁移,不能外推成「平均每个客户 46 个附件」;312 MB 也只是这一次的总量,不是配额承诺。附件迁移做得好不好,最终看的是客户能不能在失败清单上找到自己的文件,而不是成功率有多高。

五、行动清单与复算验收

  • 导入前确认源附件的可访问性:直链、签名、登录态各抽几个试下载
  • 把单文件 50 MB、单次 500 MB、8 类白名单写进导入向导第一步
  • 为每个文件记录策略:下载重传、保留外链、明确跳过
  • 下载器识别 302 到登录页与 200 但内容为 HTML 的假成功
  • 扩展名与 MIME 双查,不一致时按更保守的一方判定
  • 批次开始预占总量,结束按实际字节校正,失败批次标待复核
  • 交付三列失败清单:文件名、原因、建议,原因用系统码
  • 把 312 ÷ 500 = 62.4% 与跳过清单一起写进迁移报告

验收标准: 随机挑一个被跳过的文件,能在失败清单里看到它的系统判定原因、客户可执行的建议,以及它在配额账上的位置。

使用边界与实操验收

边界一:本篇只管附件搬运,不管备份恢复。 备份、快照与灾难恢复属于独立开发者的资产韧性:一个人的账号、数据与恢复能力(10 篇) ;附件进了你的存储,不等于它进了你的备份策略。

边界二:不要承诺「全部原样搬过来」。 单文件上限、单次总量、类型白名单任何一条都会让这句话不成立;正确说法是「在限额内尽量搬,超出的给清单和建议」。

边界三:保留外链不是保留文件。 外链依赖源系统的账号、权限与合同期,任何一项变化都会让链接失效;它只适合作为过渡,不适合作为交付。

边界四:50 MB 与 500 MB 是教学假设。 它们只用来演示限额与预占的算法,不代表任何厂商的真实配额;接入具体服务时以其官方文档为准。

边界五:附件的删除与法定导出不在本篇。 客户要求删除附件、或依据可携带权索取副本时,走隐私组的流程;本篇只讨论迁移时的搬运与限额,不构成法律意见。

关键参考与核验范围

  • OWASP File Upload Cheat Sheet :上传校验、类型白名单与存储隔离的通用清单,对应本篇的扩展名与 MIME 双查。
  • MDN MIME 类型 :MIME 类型的定义与常见误报,用于解释为什么不能只看扩展名。
  • Notion 数据导入 :导入时附件与文件如何处理的产品说明,可对照「元数据进来、字节没进来」的现象。
  • Trello 数据导入 :看板导入的官方说明,用于对照附件与外链在不同产品里的边界。

以上链接于 2026-10-26 实测可公开访问;未核验版本、价格与配额。核验日期:2026-10-26。

本篇核验的是「附件迁移的策略、限额判定与失败清单」这一层:三种策略的适用条件、单文件与单次总量的预占算法、8 类白名单的双查口径。未核验任何具体厂商的配额数值、对象存储的计费方式,也未验证各产品当前版本的导入界面;引用产品文档只用于对照行为,不作为配额依据。

系列导航

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「Indie」更多文章

  1. 开源项目验收:十项能力、四维评分与三种不该开源的项目
  2. 治理、fork 与退出:17 位贡献者、82% 的提交与一次改协议的代价
  3. 双许可与企业版:九家询价、两家成交与 4,800 美元