题干与适用场景
这道后端题考察 HTTP 部分响应、对象存储读取和下载状态机。重点不是把请求头转发给存储,而是保证范围、实体版本、压缩编码、权限和并发下载在失败与重试后仍然一致。
面试官考察什么
- 能否正确解析单范围请求,并构造 206、Content-Range、Content-Length 与 Accept-Ranges。
- 能否用 ETag 或 Last-Modified 配合 If-Range,避免客户端拼接不同版本的文件。
- 能否处理无效范围、过期签名、对象删除、限流和多分段成本。
- 能否设计校验、可观测性和权限边界,避免把下载接口变成任意对象读取器。
回答前需要澄清的问题
先确认对象是否可公开访问、最大文件大小、是否需要多范围响应、存储是否支持原生 Range、是否允许压缩传输,以及客户端是否保存 ETag。还要确认下载链接有效期、并发分段上限、完整性校验算法和资源版本变化时的产品行为。
30 秒回答框架
我会先鉴权并锁定对象版本,读取大小、ETag 和媒体类型。无 Range 时返回 200;一个合法范围返回 206 与精确 Content-Range;越界或语法无效返回 416 并给出当前长度。If-Range 不匹配时返回完整当前版本,让客户端重新开始。每个分段都受并发和速率限制,响应与最终文件用版本和校验和验证,日志记录范围、命中、耗时和失败原因。
分步骤深入解答
1. 固定表示与权限边界
先根据用户、租户和对象 id 做授权,不能让客户端直接把任意路径映射到存储键。读取对象元数据并固定一个版本标识、总字节数、Content-Type、Content-Encoding 和 ETag。若对象会变更,优先使用不可变版本或版本化存储,避免同一下载期间元数据和内容漂移。
2. 解析范围并构造响应
支持 bytes=start-end、bytes=start- 和 bytes=-suffix 三种单范围形式,校验整数、溢出和总长度。合法范围裁剪到资源边界后返回 206、Content-Range 和准确长度;没有 Range 返回 200;没有任何可满足范围返回 416,并发送 Content-Range: bytes */total。多范围需求应明确拒绝、拆成多个请求或采用 multipart 方案,不要悄悄返回错误片段。
3. 处理 If-Range 与编码
If-Range 中的强 ETag 或日期只有在仍匹配当前表示时才允许发送部分响应;不匹配则忽略 Range,返回完整当前表示。范围应针对实际传输的字节表示定义,不能先对压缩后字节做范围再让客户端按未压缩文件拼接。需要压缩时应明确是否禁用动态压缩,或让每种编码拥有独立版本和校验。
4. 控制并发、成本和失败恢复
限制每个用户、租户和对象的并发分段数、总带宽和最小范围大小,防止大量小范围请求放大存储成本。分段失败可用相同版本和范围重试;签名过期时重新签发,但不能改变对象版本。对象删除或权限变化应停止后续分段,并让客户端丢弃不完整文件而不是静默拼接。
5. 验证完整性与可观测性
客户端下载后按对象版本、总长度和校验和验证,必要时逐段校验再合并。服务端记录规范化范围、版本、状态码、字节数、存储延迟、缓存命中和重试次数,不记录下载凭证。测试空范围、负后缀、超过长度、对象更新、并发重试、断网恢复和不同 Content-Encoding,确认 206 不会返回错误版本。
高质量示范回答
我会在授权后读取一个不可变对象版本,并返回大小、ETag、类型和编码。解析单个 bytes 范围:合法时返回 206、Content-Range 和 Content-Length;无范围返回 200;不可满足时返回 416 与 bytes */total。If-Range 版本不匹配就忽略 Range,返回完整当前版本,避免客户端把不同版本拼在一起。每个用户和对象限制分段并发、速率和最小范围,失败只按相同版本重试。客户端下载后用总长度、版本和校验和验证,服务端观测范围、状态、存储延迟和重试。
常见错误
- 只转发 Range,不校验授权、对象版本和范围整数溢出。
- 对越界范围返回 200 或空响应,而不是明确的 416。
- 忽略 If-Range,导致对象更新后客户端拼出混合版本。
- 对压缩表示按错误的字节坐标切片,客户端下载后无法合并。
- 允许无限小分段和无限并发,把一次下载放大成存储风暴。
- 只检查 HTTP 状态码,不校验总长度、ETag 和最终校验和。
追问及应对
为什么不能总是返回 206?
没有 Range 时客户端请求的是完整表示,应返回 200。即使有 Range,也要确认范围可满足;否则 416 能让客户端根据当前长度修正请求。
If-Range 和 If-Match 有什么区别?
If-Range 主要决定是否继续部分传输:匹配就返回 206,不匹配就返回完整表示。If-Match 是条件请求前置条件,失败通常意味着不执行目标操作,语义不同。
多范围请求应该怎么处理?
先评估客户端和存储是否真的需要。可以拆成多个受限请求,也可以实现 multipart/byteranges;若成本和复杂度不值得,应明确拒绝而不是返回第一个范围造成误解。
如何防止下载链接被滥用?
短时签名绑定用户、对象、版本和权限,服务端再次校验租户边界,并限制并发、速率、范围数量和总字节。撤销权限或对象删除后,后续范围请求立即失效。