题干与适用场景
客户端要上传数 GB 文件,网络可能中断,移动端会重试甚至并发提交同一分片。服务需要让客户端查询上传进度、补传缺失分片,并在最终提交前后保证内容完整。面试重点是协议状态、幂等、校验、生命周期和对象可见性。
面试官考察什么
面试官会看你能否把一次大请求拆成可恢复的会话。Google Cloud 文档把可恢复上传定义为分多次请求传输,通信失败后继续;Amazon S3 multipart upload 则要求先上传分片,再显式 complete 才组装对象,并建议用生命周期规则清理未完成上传。高质量回答还要说明授权、限速和重复完成的语义。
回答前要澄清的问题
先确认对象大小、分片大小和并发上限;客户端是否能保存会话 URL;对象是否允许覆盖、版本化或仅新建;完整性校验由客户端提供整文件摘要还是服务端计算;上传会话的保留时间、取消方式、恶意占用和租户配额如何定义。不要把预签名 URL 当成自动具备业务授权。
30 秒回答框架
可以这样开场:“我把上传拆成创建会话、上传分片、查询状态、完成和取消五类操作。会话绑定租户、对象键、大小、分片规则、过期时间和校验策略;每个分片以 (uploadId, partNumber, checksum) 幂等,完成时服务端校验连续分片和整文件摘要,成功后原子地发布对象版本。超时会话由后台清理,权限、配额和限速在创建与每次分片请求都检查。”
分步骤深入分析
第一步:创建并授权上传会话
POST /uploads 校验租户配额、对象大小、内容类型和目标权限,返回随机 uploadId、分片大小、过期时间和每片上传凭证。会话记录预期大小、对象键、版本策略和校验算法;客户端不能自行指定任意存储路径。
第二步:设计分片幂等与状态查询
PUT /uploads/{id}/parts/{n} 携带分片长度和校验值。服务端按 uploadId + partNumber 保存最新合法分片元数据,重复请求同一摘要返回成功,摘要不同则返回冲突并要求客户端重新读取状态。GET /uploads/{id} 返回已确认分片、大小和下一步动作,不泄露其他租户信息。
第三步:校验数据完整性
每片先校验长度与分片摘要,完成时再验证分片列表连续性、总长度和整文件摘要。Amazon S3 文档说明可以使用分片或组合校验值;校验失败时不能发布最终对象。摘要算法和编码格式要写入会话,避免客户端与服务端解释不同。
第四步:完成与可见性
POST /uploads/{id}/complete 携带有序分片清单和可选整文件摘要。完成操作必须幂等:同一清单重复提交返回同一对象版本,冲突清单拒绝。只有存储完成组装且校验通过后,数据库中的对象记录才从 UPLOADING 变为 READY,读取接口不暴露半成品。
第五步:取消、过期与孤儿清理
客户端可显式取消;后台按过期时间扫描未完成会话并调用存储端 abort,删除已上传分片。清理任务也要幂等并可重试,记录最后错误和成本指标。S3 文档提醒未完成分片会产生存储费用,因此生命周期规则是最后一道防线,不应取代应用状态管理。
第六步:安全、配额与可观测性
每次操作校验租户、对象权限、会话状态和分片范围;凭证只允许访问当前会话,且设置短过期时间。限制单租户并发会话、总字节数和单片大小,防止资源耗尽。监控会话成功率、重试、校验失败、过期清理延迟和孤儿字节数,并按租户隔离告警。
高质量示范回答
“我会先用 POST /uploads 创建会话,校验租户配额和对象大小,生成随机 uploadId、固定分片大小、校验算法和 24 小时过期时间。每片请求带编号、长度和摘要,服务端将 (uploadId, partNumber) 作为幂等键;重复且摘要相同就返回已有结果,摘要不同则拒绝。客户端用状态接口找出缺失分片。完成请求携带有序清单和整文件摘要,服务端验证连续编号、总长度和每片摘要,再调用对象存储 complete;只有组装成功后才把对象记录标成 READY。重复完成返回同一版本,冲突清单不改变状态。取消和后台过期任务都会 abort 未完成上传并重试,避免孤儿分片持续计费。所有凭证按租户和会话隔离,创建、分片和完成都执行配额、权限、限速与审计。”
常见错误与改进
- 把上传做成一个长请求: 使用会话和分片,让网络失败只影响缺失部分。
- 只记录已上传字节数: 记录分片编号、摘要和版本,避免重复或乱序覆盖。
- 完成时直接标记成功: 先完成存储端组装并校验,再发布
READY对象。 - 忽略过期分片成本: 提供取消、后台 abort 和存储生命周期清理三层保障。
追问及应对
客户端并发上传同一分片怎么办?
按会话和分片编号串行化元数据更新,或者用条件写入。摘要相同的重复请求返回幂等成功,摘要不同返回冲突,客户端先刷新状态再重传。
完成请求超时,但对象存储其实已经完成怎么办?
为完成操作保存幂等键和目标版本,重试时先查询存储与本地状态。若已完成且清单一致,返回同一版本;若状态不确定,保持 COMPLETING 并由后台协调,不能盲目重新组装。
如何限制恶意客户端占满存储?
创建会话时预留配额,按租户限制活动会话、总分片字节、并发和过期时长;分片凭证绑定会话和范围,过期会话及时 abort,并对异常重试率告警。
是否应该允许覆盖同名对象?
默认使用新版本或条件写入。若业务允许覆盖,要求客户端提供目标版本或 If-Match 条件,完成后再原子更新引用,避免慢上传覆盖较新的对象。