题干与适用场景
API 返回很大的 JSON 文档,客户端保存了上一个 ETag。请说明何时可以使用 HTTP 226 IM Used,客户端与服务端需要交换哪些头部,以及增量无法应用时如何保证正确性。回答应覆盖协议协商、缓存和降级,不要求实现某个差分算法。
面试官考察点
- 是否理解 226 是对 GET 表示差分结果的状态码,而非“请求成功但内容不完整”。
- 是否能把
A-IM、IM、ETag与可选的Delta-Base串成完整往返。 - 是否识别基准版本、缓存并发、算法成本和回退到完整 200 的边界。
- 是否能指出实际部署前要验证客户端、中间缓存和实现支持度。
回答前需要澄清的问题
- 客户端是否能执行约定的 instance manipulation 算法,还是只能接受普通 JSON?
- 文档是否有稳定的 ETag,增量生成的 CPU 与带宽收益是否值得?
- 请求是否经过会改写或缓存响应的代理,是否允许返回带差分语义的表示?
- 旧基准失效、差分过大或校验失败时,是否可以透明地重新获取完整表示?
30 秒回答框架
我会先把 226 当作能力协商后的优化路径。客户端带上 A-IM 和基准表示的 If-None-Match;服务端只有在支持该算法且能定位基准时,才返回 226、IM、新 ETag,必要时带 Delta-Base。客户端验证基准 ETag 后合并差分并校验新实体标签。任何不匹配、成本不划算或客户端不支持的情况都返回完整 200,并记录命中率、差分大小和失败原因。缓存只接受基准与响应元数据都满足条件的结果。
分步骤深入解答
1. 先协商差分能力
A-IM 列出客户端接受的 instance manipulation;服务端选择算法后在响应 IM 中声明。它与内容编码压缩不同:压缩改变传输编码,差分改变表示内容的生成方式。没有可接受算法时应走普通 200。
2. 固定基准并绑定版本
客户端通过 If-None-Match 指定本地实体标签。服务端必须确认该标签对应的基准表示,不能只按时间或客户端自报版本猜测。响应携带新 ETag;Delta-Base 可用于明确差分所基于的标签。客户端合并后要校验结果与新标签一致。
3. 设计安全回退
基准不存在、差分大于完整文档、算法超时、合并校验失败或代理不可靠时,返回完整 200。客户端也应把基准标记为不可用并重新同步,避免把错误差分继续应用到后续版本。服务端可设置大小、CPU 和时间阈值。
4. 处理缓存与可观测性
缓存键必须覆盖 URL、协商头和能决定基准的条件;不能把只对某个 ETag 有效的差分当作通用响应。监控 226 命中率、差分与完整响应字节数、合并失败、回退比例和生成耗时,持续验证收益。
高质量示范回答
我会把它作为一个有明确回退的协议优化。客户端先声明支持的 A-IM 算法,并用 If-None-Match 指向本地基准。服务端检查基准是否仍可用、算法是否在允许列表中,再比较差分大小和生成成本;满足条件才返回 226,并用 IM 告知算法、新 ETag 标识结果,必要时用 Delta-Base 标识基准。客户端验证基准标签、合并差分、校验新实体标签后才替换本地文档。任何版本不匹配、差分过大、校验失败或链路不支持都回退到 200。缓存按协商能力与基准条件隔离,监控节省字节、CPU、失败和回退。这样既保留增量传输的收益,也不会把差分机制当成可靠性前提。
常见错误
- 把 226 当成 206,忽略 206 是 Range 请求的部分内容。
- 只发送一个“版本号”,没有用 ETag 绑定确切基准。
- 假设所有浏览器、代理和缓存都会自动理解差分。
- 不比较差分与完整文档大小,导致 CPU 增加而流量没有下降。
- 合并失败后继续沿用旧基准,而不是重新获取完整表示。
- 把压缩、JSON Patch 和 RFC 3229 的 instance manipulation 混为同一层协议。
追问及应对
226 与 206、304 有什么区别?
206 响应 Range 请求的字节区间;304 表示条件请求下无需传输新表示;226 表示服务端返回了基于某个已有表示的差分结果。三者的请求条件、客户端处理和缓存语义不同。
基准 ETag 过期时怎么办?
不能盲目套用差分。服务端应返回完整 200,或先让客户端获取当前基准;客户端清除不可用基准并从完整表示重新建立缓存。
如何防止差分缓存污染?
严格绑定 URL、协商算法、基准 ETag 和响应 ETag,校验 IM 与 Delta-Base,避免代理复用只对特定基准有效的响应,并对合并后的实体做完整性检查。