
大文件下载到一半断线,最直观的实现是读取本地文件大小,再用 Range 请求剩余内容。但对象路径不是内容的永久标识:如果下载期间有人覆盖了同名对象,前半段来自旧文件、后半段来自新文件,最终长度甚至可能完全正确。
可靠的续传至少需要三个条件:对象身份一致、返回区间正确、实际收到的字节数正确。本文以直连腾讯云 COS 的普通二进制对象为例,使用 If-Match 约束对象身份,先把响应放进独立临时文件,校验后才追加。
根据 COS 的 GET Object 官方文档:
Range 使用从零开始、包含首尾的字节偏移,只支持单一区间。206 Partial Content,并带有 Content-Range。If-Match 指定的值与当前对象 ETag 不一致时,返回 412 Precondition Failed。versionId 请求参数下载指定版本;不指定时下载最新版本。例如 bytes=8-14 一共是 7 个字节,而不是 6 个。Content-Range: bytes 8-14/16 中的 16 是完整对象大小,不能用这次响应的 Content-Length: 7 代替。
ETag 在这里作为条件请求的校验标识使用,不应把任意对象的 ETag 都当成本地文件 MD5。若业务要求确认下载的是某个确切历史版本,应使用 versionId,并确保该版本仍然可访问。
准备一个专用测试对象,内容为 0123456789abcdef,正好 16 字节,没有换行。不要使用生产对象做覆盖实验。
以下命令在 Bash 中执行。URL 填写该测试对象可读取的 HTTPS 地址;私有对象使用有效的 GET 预签名 URL,不要为了实验开放整个存储桶。签名若约束了请求头,签名时的头部必须与实际请求一致。URL 包含临时凭证,不能写入工单或公开日志。
# 读取前 8 字节,只写测试目录下的新文件
curl --silent --show-error --fail \
--header 'Range: bytes=0-7' \
--dump-header first.headers \
--output first.part \
"$URL"继续前先核对:命令成功、状态码为 206、Content-Range 为 bytes 0-7/16、文件长度为 8。记录响应中的 ETag 原始值,包括双引号。如果实际响应不同,就停止,不要把它当成可续传的首段。
接着把拿到的 ETag 填入环境变量,申请第二段:
# 将实际 ETag(含双引号)赋给 ETAG 后执行
curl --silent --show-error --fail \
--header "If-Match: $ETAG" \
--header 'Range: bytes=8-15' \
--dump-header next.headers \
--output next.part \
"$URL"本文不展示虚构的云端执行结果。预期是:对象未变化时收到 206、区间为 bytes 8-15/16、临时文件为 8 字节。满足全部条件后,才可以在测试目录合并:
cat first.part next.part > result.bin
printf '0123456789abcdef' > expected.bin
cmp expected.bin result.bincmp 无差异退出才表示该测试对象逐字节一致。上面的命令是协议实验,不是可直接用于生产的自动续传器:不能省略中间的头部和长度检查。
重新保留首段,然后将远端测试对象覆盖为 ABCDEFGHIJKLMNOP,长度仍然是 16 字节。继续携带旧 ETag 请求第二段。
如果 ETag 已改变,预期返回 412。此时不要追加任何内容,也不要去掉 If-Match 再试;应废弃旧续传状态,重新获取对象元数据并从头开始。保留或删除旧临时文件可由业务决定,但绝不能把它标记成完成。
这个实验验证的是“拒绝混合版本”,不是“请求最终成功”。只比较最终长度,会漏掉这种同长度覆盖。
还应检查两个失败分支:
生产实现需要持久化稳定的对象定位信息、ETag、总长度和已确认写入的偏移。有版本控制时,同时保存 versionId。不要把会过期的预签名 URL 当作唯一对象身份;更新授权不等于允许切换对象版本。
每次请求的处理顺序应当是:
If-Match。崩溃恢复也要维护这个顺序:如果数据已经追加、偏移记录却尚未更新,重启后不能直接从文件末尾继续。应依据持久化提交点处理未确认尾部,或者保存独立分段及提交清单。否则网络层正确,磁盘恢复仍可能产生重复字节。
上述实验面向 COS 直连地址。不使用自动跟随重定向,也不启用自动解压;代理转码、压缩转换或缓存策略可能改变返回内容与字节偏移的关系。若经由 CDN 或业务网关下载,必须针对实际链路重新验证 Range 和条件请求行为。
排障时保留状态码、Content-Range、ETag 和 x-cos-request-id,但不要记录完整签名 URL。下载实验会产生请求与流量,费用以实际配置和购买页为准。
真正的完成条件不是“重试后没有异常”,而是“每个已提交字节都属于预期对象,并且最终内容通过校验”。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。